This is xnu-12377.1.9. See this file in:
/*
* Copyright (c) 2024 Apple Inc. All rights reserved.
*
* @APPLE_OSREFERENCE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. The rights granted to you under the License
* may not be used to create, or enable the creation or redistribution of,
* unlawful or unlicensed copies of an Apple operating system, or to
* circumvent, violate, or enable the circumvention or violation of, any
* terms of an Apple operating system software license agreement.
*
* Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_OSREFERENCE_LICENSE_HEADER_END@
*/
/*
* vm/configurator_test.c
*
* Test vm_configurator itself.
*
* Verify that the VM states generated by vm_configurator are correct.
* This is intended to catch bugs in vm_configurator's
* template and checker system, as well as bugs in individual
* configurations used by other tests.
*/
#include "configurator/vm_configurator_tests.h"
T_GLOBAL_META(
T_META_NAMESPACE("xnu.vm.configurator"),
T_META_RADAR_COMPONENT_NAME("xnu"),
T_META_RADAR_COMPONENT_VERSION("VM"),
T_META_RUN_CONCURRENTLY(true),
T_META_ASROOT(true), /* required for vm submap sysctls */
T_META_ALL_VALID_ARCHS(true)
);
/*
* Return true if [start, start + size) is a VM entry at the given submap depth.
*/
__attribute__((overloadable))
static bool
is_entry(mach_vm_address_t start, mach_vm_size_t size, uint32_t submap_depth)
{
mach_vm_address_t entry_start = start;
mach_vm_size_t entry_size;
vm_region_submap_info_data_64_t info;
if (!get_info_for_address(&entry_start, &entry_size, &info, submap_depth)) {
return false; /* not mapped */
}
if (entry_start != start || entry_size != size) {
return false; /* mapped, but wrong extent */
}
return true;
}
/*
* Return true if [start, start + size) is a VM entry at submap depth 0.
*/
__attribute__((overloadable, used))
static bool
is_entry(mach_vm_address_t start, mach_vm_size_t size)
{
return is_entry(start, size, 0);
}
/*
* Return true if [start, start + size) is an unallocated hole
* at the given submap depth.
*/
__attribute__((overloadable))
static bool
is_hole(mach_vm_address_t start, mach_vm_size_t size, uint32_t submap_depth)
{
mach_vm_address_t entry_start = start;
mach_vm_size_t entry_size;
vm_region_submap_info_data_64_t info;
if (get_info_for_address(&entry_start, &entry_size, &info, submap_depth)) {
/* start address was mapped */
return false;
} else if (entry_start < start + size) {
/* some address before the end of the expected hole was mapped */
return false;
}
/* [start, start + size) was entirely unmapped */
return true;
}
/*
* Return true if [start, start + size) is an unallocated hole at submap depth 0.
* Unallocate space inside a submap does not count.
*/
__attribute__((overloadable, used))
static bool
is_hole(mach_vm_address_t start, mach_vm_size_t size)
{
return is_hole(start, size, 0 /* submap_depth */);
}
/*
* Verify the memory and the checker for an expected hole.
*/
static void
assert_hole_checker_and_entry(
vm_entry_checker_t *checker,
mach_vm_address_t start,
mach_vm_size_t size)
{
assert(start % PAGE_SIZE == 0);
assert(size % PAGE_SIZE == 0);
assert(checker->kind == Hole);
assert(checker->address == start);
assert(checker->size == size);
assert(is_hole(start, size, checker->submap_depth));
}
/*
* Verify the checker for an expected allocated entry.
* Does not verify the actual VM state.
*/
static void
assert_allocation_checker(
vm_entry_checker_t *checker,
mach_vm_address_t start,
mach_vm_size_t size)
{
assert(start % PAGE_SIZE == 0);
assert(size % PAGE_SIZE == 0);
assert(checker->kind == Allocation);
assert(checker->address == start);
assert(checker->size == size);
}
/*
* Verify the actual VM state for an expected allocated entry.
* Does not verify the matching checker.
* Returns the vm_region output for the memory.
*/
static void
assert_allocation_entry(
mach_vm_address_t start,
mach_vm_size_t size,
uint32_t submap_depth,
vm_region_submap_info_data_64_t * const out_info)
{
mach_vm_address_t entry_start = start;
mach_vm_size_t entry_size;
assert(get_info_for_address(&entry_start, &entry_size, out_info, submap_depth));
assert(entry_start == start);
assert(entry_size == size);
}
/*
* Verify the memory and the checker for an expected allocated entry.
* Returns the vm_region output for the memory.
*/
static void
assert_allocation_checker_and_entry(
vm_entry_checker_t *checker,
mach_vm_address_t start,
mach_vm_size_t size,
vm_region_submap_info_data_64_t * const out_info)
{
assert_allocation_checker(checker, start, size);
assert_allocation_entry(start, size, checker->submap_depth, out_info);
}
/*
* Verify that checker_list consists of a pattern of entries and holes
* Each allocation or hole is assumed to be DEFAULT_ENTRY_SIZE in length.
* "##.#..#": allocation, allocation, hole, allocation, hole, hole, allocation
*/
static void
assert_allocation_and_hole_pattern(
checker_list_t *checker_list,
const char *pattern)
{
mach_vm_address_t base = checker_range_start_address(checker_list->entries);
assert(checker_range_count(checker_list->entries) == strlen(pattern));
for (size_t i = 0; i < strlen(pattern); i++) {
vm_region_submap_info_data_64_t info;
mach_vm_address_t entry_address = base + i * DEFAULT_ENTRY_SIZE;
vm_entry_checker_t *checker = checker_list_nth(checker_list, i);
switch (pattern[i]) {
case '#':
assert_allocation_checker_and_entry(checker,
entry_address, DEFAULT_ENTRY_SIZE, &info);
break;
case '.':
assert_hole_checker_and_entry(checker,
entry_address, DEFAULT_ENTRY_SIZE);
break;
default:
T_ASSERT_FAIL("pattern character '%c' is neither '#' nor '.'", pattern[i]);
break;
}
}
}
static void
assert_checker_and_entry_protection_equals(
vm_entry_checker_t *checker,
vm_region_submap_info_data_64_t *info,
int protection,
int max_protection)
{
assert(checker->protection == protection);
assert(checker->max_protection == max_protection);
assert(info->protection == protection);
assert(info->max_protection == max_protection);
}
/*
* Verify the memory and the checker for an expected permanent entry.
* This is destructive because it attempts to deallocate the permanent entry
* which makes its memory inaccessible, and updates the checker to match.
*/
static void
destructively_assert_permanent_checker_and_entry(
vm_entry_checker_t *checker,
mach_vm_address_t start,
mach_vm_size_t size)
{
assert(start % PAGE_SIZE == 0);
assert(size % PAGE_SIZE == 0);
assert(checker->permanent == true);
assert(checker->address == start);
assert(checker->size == size);
/*
* Permanent memory is indistinguishable in vm_region output.
* We can only try to deallocate it and then see if it is still there.
*/
/* check that it exists */
assert(is_entry(start, size, checker->submap_depth));
/* try to deallocate it */
kern_return_t kr = mach_vm_deallocate(mach_task_self(), start, size);
assert(kr == 0);
/* check that it still exists */
assert(is_entry(start, size, checker->submap_depth));
/* update the checker because the memory is now inaccessible */
checker->protection = VM_PROT_NONE;
checker->max_protection = VM_PROT_NONE;
}
/*
* Verify the memory and checker for an expected non-permanent allocation.
* This is destructive because it deallocates the memory
* and updates the checker to match.
*/
static void
destructively_assert_nonpermanent_checker_and_entry(
checker_list_t *list,
vm_entry_checker_t *checker,
mach_vm_address_t start,
mach_vm_size_t size)
{
assert(start % PAGE_SIZE == 0);
assert(size % PAGE_SIZE == 0);
assert(checker->permanent == false);
assert(checker->address == start);
assert(checker->size == size);
/*
* Permanent memory is indistinguishable in vm_region output.
* We can only try to deallocate it and then see if it is still there.
*/
/* check that it exists */
assert(is_entry(start, size, checker->submap_depth));
/* try to deallocate it */
kern_return_t kr = mach_vm_deallocate(mach_task_self(), start, size);
assert(kr == 0);
/* check that it no longer exists */
assert(!is_entry(start, size, checker->submap_depth));
assert(is_hole(start, size, 0 /* submap_depth */));
/*
* Update the checker to match the now-deallocated memory.
* The checker should be replaced by a hole checker.
*
* Save the checker's index first so we can
* look up and verify the hole checker after.
*/
unsigned index = 0;
while (checker_list_nth(list, index) != checker) {
index++;
}
checker_list_free_checker(list, checker);
vm_entry_checker_t *new_hole = checker_list_nth(list, index);
assert_hole_checker_and_entry(new_hole, start, size);
}
/*
* Verify the memory and the checker for an expected submap entry.
* Does not examine the contents of the submap.
* Returns the vm_region output for the entry in the parent map.
*/
static void
assert_submap_checker_and_entry(
vm_entry_checker_t *checker,
mach_vm_address_t start,
mach_vm_size_t size,
vm_region_submap_info_data_64_t * const out_info)
{
assert(start % PAGE_SIZE == 0);
assert(size % PAGE_SIZE == 0);
assert(checker->kind == Submap);
assert(checker->address == start);
assert(checker->size == size);
assert(checker->submap_depth == 0); /* nested submaps not allowed */
mach_vm_address_t entry_start = start;
mach_vm_size_t entry_size;
assert(get_info_for_address(&entry_start, &entry_size, out_info, checker->submap_depth));
assert(entry_start == start);
assert(entry_size == size);
}
static test_result_t
test_single_entry_1(
checker_list_t *checker_list,
mach_vm_address_t start,
mach_vm_size_t size)
{
/* test range is a single allocation */
vm_entry_checker_t *checker = checker_list_nth(checker_list, 0);
vm_region_submap_info_data_64_t info;
assert_allocation_checker_and_entry(checker, start, size, &info);
return TestSucceeded;
}
static test_result_t
test_single_entry_2(
checker_list_t *checker_list,
mach_vm_address_t start,
mach_vm_size_t size)
{
vm_entry_checker_t *checker = checker_list_nth(checker_list, 0);
vm_region_submap_info_data_64_t info;
/* test range excludes the end of the allocation */
assert(size == DEFAULT_ENTRY_SIZE - DEFAULT_PARTIAL_ENTRY_SIZE);
assert_allocation_checker_and_entry(checker,
start, DEFAULT_ENTRY_SIZE, &info);
return TestSucceeded;
}
static test_result_t
test_single_entry_3(
checker_list_t *checker_list,
mach_vm_address_t start,
mach_vm_size_t size)
{
vm_entry_checker_t *checker = checker_list_nth(checker_list, 0);
vm_region_submap_info_data_64_t info;
/* test range excludes the start of the allocation */
assert(size == DEFAULT_ENTRY_SIZE - DEFAULT_PARTIAL_ENTRY_SIZE);
assert_allocation_checker_and_entry(checker,
start - DEFAULT_PARTIAL_ENTRY_SIZE, DEFAULT_ENTRY_SIZE, &info);
return TestSucceeded;
}
static test_result_t
test_single_entry_4(
checker_list_t *checker_list,
mach_vm_address_t start,
mach_vm_size_t size)
{
vm_entry_checker_t *checker = checker_list_nth(checker_list, 0);
vm_region_submap_info_data_64_t info;
/* test range excludes the start and end of the allocation */
assert(size == DEFAULT_ENTRY_SIZE - DEFAULT_PARTIAL_ENTRY_SIZE);
assert_allocation_checker_and_entry(checker,
start - DEFAULT_PARTIAL_ENTRY_SIZE / 2, DEFAULT_ENTRY_SIZE, &info);
return TestSucceeded;
}
static test_result_t
test_multiple_entries_1(
checker_list_t *checker_list,
mach_vm_address_t start,
mach_vm_size_t size)
{
assert_allocation_and_hole_pattern(checker_list, "##");
assert(start == checker_range_start_address(checker_list->entries));
assert(size == DEFAULT_ENTRY_SIZE * 2);
return TestSucceeded;
}
static test_result_t
test_multiple_entries_2(
checker_list_t *checker_list,
mach_vm_address_t start,
mach_vm_size_t size)
{
assert_allocation_and_hole_pattern(checker_list, "###");
assert(start == checker_range_start_address(checker_list->entries));
assert(size == DEFAULT_ENTRY_SIZE * 3);
return TestSucceeded;
}
static test_result_t
test_multiple_entries_3(
checker_list_t *checker_list,
mach_vm_address_t start,
mach_vm_size_t size)
{
assert_allocation_and_hole_pattern(checker_list,
"############"
"############"
"############"
"############");
assert(start == checker_range_start_address(checker_list->entries));
assert(size == DEFAULT_ENTRY_SIZE * 4 * 12);
return TestSucceeded;
}
static test_result_t
test_multiple_entries_4(
checker_list_t *checker_list,
mach_vm_address_t start,
mach_vm_size_t size)
{
assert_allocation_and_hole_pattern(checker_list, "###");
assert(start == checker_range_start_address(checker_list->entries));
assert(size == DEFAULT_ENTRY_SIZE * 3 - DEFAULT_PARTIAL_ENTRY_SIZE);
return TestSucceeded;
}
static test_result_t
test_multiple_entries_5(
checker_list_t *checker_list,
mach_vm_address_t start,
mach_vm_size_t size)
{
assert_allocation_and_hole_pattern(checker_list, "###");
assert(start == checker_range_start_address(checker_list->entries) + DEFAULT_PARTIAL_ENTRY_SIZE);
assert(size == DEFAULT_ENTRY_SIZE * 3 - DEFAULT_PARTIAL_ENTRY_SIZE);
return TestSucceeded;
}
static test_result_t
test_multiple_entries_6(
checker_list_t *checker_list,
mach_vm_address_t start,
mach_vm_size_t size)
{
assert_allocation_and_hole_pattern(checker_list, "###");
assert(start == checker_range_start_address(checker_list->entries) + DEFAULT_PARTIAL_ENTRY_SIZE / 2);
assert(size == DEFAULT_ENTRY_SIZE * 3 - DEFAULT_PARTIAL_ENTRY_SIZE);
return TestSucceeded;
}
static test_result_t
test_some_holes_1(
checker_list_t *checker_list,
mach_vm_address_t start,
mach_vm_size_t size)
{
assert_allocation_and_hole_pattern(checker_list, ".#");
assert(start == checker_range_start_address(checker_list->entries));
assert(size == DEFAULT_ENTRY_SIZE * 2);
return TestSucceeded;
}
static test_result_t
test_some_holes_2(
checker_list_t *checker_list,
mach_vm_address_t start,
mach_vm_size_t size)
{
assert_allocation_and_hole_pattern(checker_list, ".###");
assert(start == checker_range_start_address(checker_list->entries));
assert(size == DEFAULT_ENTRY_SIZE * 4);
return TestSucceeded;
}
static test_result_t
test_some_holes_3(
checker_list_t *checker_list,
mach_vm_address_t start,
mach_vm_size_t size)
{
assert_allocation_and_hole_pattern(checker_list, ".#");
assert(start == checker_range_start_address(checker_list->entries));
assert(size == DEFAULT_ENTRY_SIZE * 2 - DEFAULT_PARTIAL_ENTRY_SIZE);
return TestSucceeded;
}
static test_result_t
test_some_holes_4(
checker_list_t *checker_list,
mach_vm_address_t start,
mach_vm_size_t size)
{
assert_allocation_and_hole_pattern(checker_list, ".###");
assert(start == checker_range_start_address(checker_list->entries));
assert(size == DEFAULT_ENTRY_SIZE * 4 - DEFAULT_PARTIAL_ENTRY_SIZE);
return TestSucceeded;
}
static test_result_t
test_some_holes_5(
checker_list_t *checker_list,
mach_vm_address_t start,
mach_vm_size_t size)
{
assert_allocation_and_hole_pattern(checker_list, "#.");
assert(start == checker_range_start_address(checker_list->entries));
assert(size == DEFAULT_ENTRY_SIZE * 2);
return TestSucceeded;
}
static test_result_t
test_some_holes_6(
checker_list_t *checker_list,
mach_vm_address_t start,
mach_vm_size_t size)
{
assert_allocation_and_hole_pattern(checker_list, "###.");
assert(start == checker_range_start_address(checker_list->entries));
assert(size == DEFAULT_ENTRY_SIZE * 4);
return TestSucceeded;
}
static test_result_t
test_some_holes_7(
checker_list_t *checker_list,
mach_vm_address_t start,
mach_vm_size_t size)
{
assert_allocation_and_hole_pattern(checker_list, "#.");
assert(start == checker_range_start_address(checker_list->entries) + DEFAULT_PARTIAL_ENTRY_SIZE);
assert(size == DEFAULT_ENTRY_SIZE * 2 - DEFAULT_PARTIAL_ENTRY_SIZE);
return TestSucceeded;
}
static test_result_t
test_some_holes_8(
checker_list_t *checker_list,
mach_vm_address_t start,
mach_vm_size_t size)
{
assert_allocation_and_hole_pattern(checker_list, "###.");
assert(start == checker_range_start_address(checker_list->entries) + DEFAULT_PARTIAL_ENTRY_SIZE);
assert(size == DEFAULT_ENTRY_SIZE * 4 - DEFAULT_PARTIAL_ENTRY_SIZE);
return TestSucceeded;
}
static test_result_t
test_some_holes_9(
checker_list_t *checker_list,
mach_vm_address_t start,
mach_vm_size_t size)
{
assert_allocation_and_hole_pattern(checker_list, "#.#");
assert(start == checker_range_start_address(checker_list->entries));
assert(size == DEFAULT_ENTRY_SIZE * 3);
return TestSucceeded;
}
static test_result_t
test_some_holes_10(
checker_list_t *checker_list,
mach_vm_address_t start,
mach_vm_size_t size)
{
assert_allocation_and_hole_pattern(checker_list, "#.#.#");
assert(start == checker_range_start_address(checker_list->entries));
assert(size == DEFAULT_ENTRY_SIZE * 5);
return TestSucceeded;
}
static test_result_t
test_some_holes_11(
checker_list_t *checker_list,
mach_vm_address_t start,
mach_vm_size_t size)
{
assert_allocation_and_hole_pattern(checker_list, "##.##.##");
assert(start == checker_range_start_address(checker_list->entries));
assert(size == DEFAULT_ENTRY_SIZE * 8);
return TestSucceeded;
}
static test_result_t
test_some_holes_12(
checker_list_t *checker_list,
mach_vm_address_t start,
mach_vm_size_t size)
{
assert_allocation_and_hole_pattern(checker_list, "###.###.###");
assert(start == checker_range_start_address(checker_list->entries));
assert(size == DEFAULT_ENTRY_SIZE * 11);
return TestSucceeded;
}
static test_result_t
test_all_holes_1(
checker_list_t *checker_list,
mach_vm_address_t start,
mach_vm_size_t size)
{
assert_allocation_and_hole_pattern(checker_list, "#.#");
assert(start == checker_range_start_address(checker_list->entries) + DEFAULT_ENTRY_SIZE);
assert(size == DEFAULT_ENTRY_SIZE);
return TestSucceeded;
}
static test_result_t
test_all_holes_2(
checker_list_t *checker_list,
mach_vm_address_t start,
mach_vm_size_t size)
{
assert_allocation_and_hole_pattern(checker_list, "#.");
assert(start == checker_range_start_address(checker_list->entries) + DEFAULT_ENTRY_SIZE);
assert(size == DEFAULT_PARTIAL_ENTRY_SIZE);
return TestSucceeded;
}
static test_result_t
test_all_holes_3(
checker_list_t *checker_list,
mach_vm_address_t start,
mach_vm_size_t size)
{
assert_allocation_and_hole_pattern(checker_list, ".#");
assert(start == checker_range_start_address(checker_list->entries) + DEFAULT_PARTIAL_ENTRY_SIZE);
assert(size == DEFAULT_PARTIAL_ENTRY_SIZE);
return TestSucceeded;
}
static test_result_t
test_all_holes_4(
checker_list_t *checker_list,
mach_vm_address_t start,
mach_vm_size_t size)
{
assert_allocation_and_hole_pattern(checker_list, ".");
assert(start == checker_range_start_address(checker_list->entries) + DEFAULT_PARTIAL_ENTRY_SIZE / 2);
assert(size == DEFAULT_PARTIAL_ENTRY_SIZE);
return TestSucceeded;
}
static test_result_t
test_null_entry(
checker_list_t *checker_list,
mach_vm_address_t start,
mach_vm_size_t size)
{
vm_entry_checker_t *checker = checker_list_nth(checker_list, 0);
vm_region_submap_info_data_64_t info;
assert_allocation_checker_and_entry(checker, start, size, &info);
/* entry's object is null */
assert(info.object_id_full == 0);
assert(checker->object->object_id == 0);
return TestSucceeded;
}
static test_result_t
test_nonresident_entry(
checker_list_t *checker_list,
mach_vm_address_t start,
mach_vm_size_t size)
{
vm_entry_checker_t *checker = checker_list_nth(checker_list, 0);
vm_region_submap_info_data_64_t info;
assert_allocation_checker_and_entry(checker, start, size, &info);
/* entry has an object, but its pages are not resident */
assert(info.object_id_full != 0);
assert(info.pages_resident == 0);
assert(checker->object->object_id != 0);
assert(checker->pages_resident == 0);
return TestSucceeded;
}
static test_result_t
test_resident_entry(
checker_list_t *checker_list,
mach_vm_address_t start,
mach_vm_size_t size)
{
vm_entry_checker_t *checker = checker_list_nth(checker_list, 0);
vm_region_submap_info_data_64_t info;
assert_allocation_checker_and_entry(checker, start, size, &info);
/* entry has an object and its pages are resident */
assert(info.pages_resident == size / PAGE_SIZE);
assert(checker->pages_resident == size / PAGE_SIZE);
assert(checker->object->object_id != 0);
return TestSucceeded;
}
/* common code for two-shared-entry tests */
static void
test_one_shared_pair(
checker_list_t *checker_list,
mach_vm_address_t left_entry_start,
mach_vm_address_t right_entry_start,
mach_vm_size_t size,
mach_vm_address_t right_object_offset)
{
/*
* Two entries, both have the same object with refcount two.
* Right entry's object offset varies.
*/
vm_entry_checker_t *left_checker =
checker_list_find_allocation(checker_list, left_entry_start);
vm_entry_checker_t *right_checker =
checker_list_find_allocation(checker_list, right_entry_start);
assert(left_checker);
assert(right_checker);
vm_region_submap_info_data_64_t left_info, right_info;
assert_allocation_checker_and_entry(left_checker, left_entry_start, size, &left_info);
assert_allocation_checker_and_entry(right_checker, right_entry_start, size, &right_info);
assert(left_info.object_id_full != 0);
assert(left_info.object_id_full == right_info.object_id_full);
assert(left_info.ref_count == 2);
assert(right_info.ref_count == 2);
assert(left_info.share_mode == SM_TRUESHARED);
assert(right_info.share_mode == SM_TRUESHARED);
assert(left_info.offset == 0);
assert(right_info.offset == right_object_offset);
assert(left_info.user_tag != right_info.user_tag);
assert(left_checker->object == right_checker->object);
/* checker doesn't distinguish SM_SHARED from SM_TRUESHARED */
assert(checker_share_mode(left_checker) == SM_SHARED);
assert(checker_share_mode(right_checker) == SM_SHARED);
assert(left_checker->object_offset == 0);
assert(right_checker->object_offset == right_object_offset);
assert(left_checker->user_tag != right_checker->user_tag);
}
static test_result_t
test_shared_entry(
checker_list_t *checker_list,
mach_vm_address_t start,
mach_vm_size_t size)
{
/* entries are both at object offset 0 */
test_one_shared_pair(checker_list, start, start + size, size, 0);
return TestSucceeded;
}
static test_result_t
test_shared_entry_discontiguous(
checker_list_t *checker_list,
mach_vm_address_t start,
mach_vm_size_t size)
{
/*
* right entry's object offset begins
* after the left entry's range ends
*/
test_one_shared_pair(checker_list, start, start + size, size, DEFAULT_ENTRY_SIZE);
return TestSucceeded;
}
static test_result_t
test_shared_entry_partial(
checker_list_t *checker_list,
mach_vm_address_t start,
mach_vm_size_t size)
{
/*
* right entry's object offset begins
* inside the left entry's range
*/
test_one_shared_pair(checker_list, start, start + size, size, DEFAULT_PARTIAL_ENTRY_SIZE);
return TestSucceeded;
}
static test_result_t
test_shared_entry_pairs(
checker_list_t *checker_list,
mach_vm_address_t start,
mach_vm_size_t size)
{
/*
* two shared pairs
*/
mach_vm_size_t entry_size = size / 4;
mach_vm_address_t one = start;
mach_vm_address_t two = one + entry_size;
mach_vm_address_t three = two + entry_size;
mach_vm_address_t four = three + entry_size;
test_one_shared_pair(checker_list, one, four, entry_size, 0);
test_one_shared_pair(checker_list, two, three, entry_size, 0);
return TestSucceeded;
}
static test_result_t
test_shared_entry_x1000(
checker_list_t *checker_list,
mach_vm_address_t start,
mach_vm_size_t size)
{
/* many entries, all of which share the same object */
entry_checker_range_t limit = checker_list_find_range(checker_list, start, size);
assert(checker_range_count(limit) == 1000);
uint64_t shared_object_id = 0;
FOREACH_CHECKER(checker, limit) {
assert(checker->object);
assert(checker->object->object_id_mode == object_has_known_id);
if (!shared_object_id) {
assert(checker->object->object_id != 0);
shared_object_id = checker->object->object_id;
}
assert(checker->object->object_id == shared_object_id);
assert(get_object_id_for_address(checker->address) == shared_object_id);
}
return TestSucceeded;
}
/* common code for two-shared-entry tests */
static test_result_t
test_cow_entry(
checker_list_t *checker_list,
mach_vm_address_t start,
mach_vm_size_t size)
{
/*
* two entries, both have the same object and its refcount is two.
* [start, start + size) is only the first entry
*/
vm_entry_checker_t *left_checker = checker_list_nth(checker_list, 0);
vm_region_submap_info_data_64_t left_info;
assert_allocation_checker_and_entry(left_checker, start, size, &left_info);
vm_entry_checker_t *right_checker = checker_list_nth(checker_list, 1);
vm_region_submap_info_data_64_t right_info;
assert_allocation_checker_and_entry(right_checker, start + size, size, &right_info);
assert(left_info.object_id_full != 0);
assert(left_info.object_id_full == right_info.object_id_full);
assert(left_info.ref_count == 2);
assert(right_info.ref_count == 2);
assert(left_info.share_mode == SM_COW);
assert(right_info.share_mode == SM_COW);
assert(left_info.offset == 0);
assert(right_info.offset == 0);
assert(left_checker->object == right_checker->object);
assert(checker_share_mode(left_checker) == SM_COW);
assert(checker_share_mode(right_checker) == SM_COW);
assert(left_checker->object_offset == 0);
assert(right_checker->object_offset == 0);
return TestSucceeded;
}
static test_result_t
test_cow_unreferenced(
checker_list_t *checker_list,
mach_vm_address_t start,
mach_vm_size_t size)
{
/*
* one COW entry with refcount 1
*/
vm_entry_checker_t *checker = checker_list_nth(checker_list, 0);
vm_region_submap_info_data_64_t info;
assert_allocation_checker_and_entry(checker, start, size, &info);
assert(info.share_mode == SM_COW);
assert(info.object_id_full != 0);
assert(info.ref_count == 1);
assert(info.offset == 0);
assert(checker->object_offset == 0);
assert(checker_share_mode(checker) == SM_COW);
assert(checker->object);
assert(checker->object->self_ref_count == 1);
return TestSucceeded;
}
/* common checks for cow_nocow and nocow_cow */
static test_result_t
test_cow_nocow_common(
vm_entry_checker_t *cow_checker,
vm_entry_checker_t *plain_checker,
mach_vm_address_t cow_start_address,
mach_vm_address_t plain_start_address,
mach_vm_size_t entry_size)
{
/* two entries: one is COW, one is not COW */
vm_region_submap_info_data_64_t cow_info, plain_info;
assert_allocation_checker_and_entry(cow_checker, cow_start_address, entry_size, &cow_info);
assert_allocation_checker_and_entry(plain_checker, plain_start_address, entry_size, &plain_info);
assert(cow_info.share_mode == SM_COW);
assert(plain_info.share_mode == SM_PRIVATE);
assert(cow_info.object_id_full != 0);
assert(cow_info.object_id_full != plain_info.object_id_full);
assert(cow_info.ref_count == 2);
assert(cow_info.offset == 0);
assert(checker_share_mode(cow_checker) == SM_COW);
assert(checker_share_mode(plain_checker) == SM_PRIVATE);
assert(cow_checker->object != NULL);
assert(cow_checker->object != plain_checker->object);
assert(cow_checker->object_offset == 0);
return TestSucceeded;
}
static test_result_t
test_cow_nocow(
checker_list_t *checker_list,
mach_vm_address_t start,
mach_vm_size_t size)
{
/*
* two entries: first is COW, second is not
*/
vm_entry_checker_t *cow_checker = checker_list_nth(checker_list, 0);
vm_entry_checker_t *plain_checker = checker_list_nth(checker_list, 1);
assert(size % 2 == 0);
mach_vm_address_t cow_start = start;
mach_vm_address_t plain_start = start + size / 2;
return test_cow_nocow_common(cow_checker, plain_checker,
cow_start, plain_start, size / 2);
}
static test_result_t
test_nocow_cow(
checker_list_t *checker_list,
mach_vm_address_t start,
mach_vm_size_t size)
{
/*
* two entries: first is not COW, second is COW
*/
vm_entry_checker_t *plain_checker = checker_list_nth(checker_list, 0);
vm_entry_checker_t *cow_checker = checker_list_nth(checker_list, 1);
assert(size % 2 == 0);
mach_vm_address_t plain_start = start;
mach_vm_address_t cow_start = start + size / 2;
return test_cow_nocow_common(cow_checker, plain_checker,
cow_start, plain_start, size / 2);
}
static test_result_t
test_cow_unreadable(
checker_list_t *checker_list,
mach_vm_address_t start,
mach_vm_size_t size)
{
/*
* COW entry, unreadable
*/
vm_entry_checker_t *checker = checker_list_nth(checker_list, 0);
vm_region_submap_info_data_64_t info;
assert_allocation_checker_and_entry(checker, start, size, &info);
assert(info.share_mode == SM_COW);
assert(info.protection == VM_PROT_NONE);
assert(info.ref_count == 2);
assert(checker_share_mode(checker) == SM_COW);
assert(checker->protection == VM_PROT_NONE);
assert(checker->object != NULL);
assert(checker->object->self_ref_count == 2);
return TestSucceeded;
}
static test_result_t
test_cow_unwriteable(
checker_list_t *checker_list,
mach_vm_address_t start,
mach_vm_size_t size)
{
/*
* COW entry, readable but unwriteable
*/
vm_entry_checker_t *checker = checker_list_nth(checker_list, 0);
vm_region_submap_info_data_64_t info;
assert_allocation_checker_and_entry(checker, start, size, &info);
assert(info.share_mode == SM_COW);
assert(info.protection == VM_PROT_READ);
assert(info.ref_count == 2);
assert(checker_share_mode(checker) == SM_COW);
assert(checker->protection == VM_PROT_READ);
assert(checker->object != NULL);
assert(checker->object->self_ref_count == 2);
return TestSucceeded;
}
static test_result_t
test_permanent_entry(
checker_list_t *checker_list,
mach_vm_address_t start,
mach_vm_size_t size)
{
destructively_assert_permanent_checker_and_entry(
checker_list_nth(checker_list, 0), start, size);
return TestSucceeded;
}
static test_result_t
test_permanent_before_permanent(
checker_list_t *checker_list,
mach_vm_address_t start,
mach_vm_size_t size)
{
destructively_assert_permanent_checker_and_entry(
checker_list_nth(checker_list, 0),
start, size / 2);
destructively_assert_permanent_checker_and_entry(
checker_list_nth(checker_list, 1),
start + size / 2, size / 2);
return TestSucceeded;
}
static test_result_t
test_permanent_before_allocation(
checker_list_t *checker_list,
mach_vm_address_t start,
mach_vm_size_t size)
{
destructively_assert_permanent_checker_and_entry(
checker_list_nth(checker_list, 0),
start, size / 2);
destructively_assert_nonpermanent_checker_and_entry(
checker_list,
checker_list_nth(checker_list, 1),
start + size / 2, size / 2);
assert_hole_checker_and_entry(
checker_list_nth(checker_list, 2),
start + size, DEFAULT_ENTRY_SIZE);
return TestSucceeded;
}
static test_result_t
test_permanent_before_allocation_2(
checker_list_t *checker_list,
mach_vm_address_t start,
mach_vm_size_t size)
{
vm_region_submap_info_data_64_t info;
destructively_assert_permanent_checker_and_entry(
checker_list_nth(checker_list, 0),
start, size / 2);
destructively_assert_nonpermanent_checker_and_entry(
checker_list,
checker_list_nth(checker_list, 1),
start + size / 2, size / 2);
assert_allocation_checker_and_entry(
checker_list_nth(checker_list, 2),
start + size, DEFAULT_ENTRY_SIZE, &info);
return TestSucceeded;
}
static test_result_t
test_permanent_before_hole(
checker_list_t *checker_list,
mach_vm_address_t start,
mach_vm_size_t size)
{
destructively_assert_permanent_checker_and_entry(
checker_list_nth(checker_list, 0),
start, size / 2);
assert_hole_checker_and_entry(
checker_list_nth(checker_list, 1),
start + size / 2, size / 2);
return TestSucceeded;
}
static test_result_t
test_permanent_after_allocation(
checker_list_t *checker_list,
mach_vm_address_t start,
mach_vm_size_t size)
{
destructively_assert_nonpermanent_checker_and_entry(
checker_list,
checker_list_nth(checker_list, 0),
start, size / 2);
destructively_assert_permanent_checker_and_entry(
checker_list_nth(checker_list, 1),
start + size / 2, size / 2);
return TestSucceeded;
}
static test_result_t
test_permanent_after_hole(
checker_list_t *checker_list,
mach_vm_address_t start,
mach_vm_size_t size)
{
assert_hole_checker_and_entry(
checker_list_nth(checker_list, 0),
start, size / 2);
destructively_assert_permanent_checker_and_entry(
checker_list_nth(checker_list, 1),
start + size / 2, size / 2);
return TestSucceeded;
}
static test_result_t
test_single_submap_single_entry_common(
checker_list_t *checker_list,
mach_vm_address_t start,
mach_vm_size_t size)
{
vm_region_submap_info_data_64_t info;
vm_entry_checker_t *submap_parent = checker_list_nth(checker_list, 0);
assert_submap_checker_and_entry(submap_parent, start, size, &info);
checker_list_t *submap_checkers DEFER_UNSLIDE =
checker_get_and_slide_submap_checkers(submap_parent);
vm_entry_checker_t *submap_content = checker_list_nth(submap_checkers, 0);
assert_allocation_checker_and_entry(submap_content, start, size, &info);
return TestSucceeded;
}
static test_result_t
test_single_submap_single_entry(
checker_list_t *checker_list,
mach_vm_address_t start,
mach_vm_size_t size)
{
return test_single_submap_single_entry_common(
checker_list, start, size);
}
static test_result_t
test_single_submap_single_entry_first_pages(
checker_list_t *checker_list,
mach_vm_address_t start,
mach_vm_size_t size)
{
/* tested range excludes the last 1/2 of the real entry */
mach_vm_size_t submap_size = size * 2;
mach_vm_address_t submap_start = start;
return test_single_submap_single_entry_common(
checker_list, submap_start, submap_size);
}
static test_result_t
test_single_submap_single_entry_last_pages(
checker_list_t *checker_list,
mach_vm_address_t start,
mach_vm_size_t size)
{
/* tested range excludes the first 1/2 of the real entry */
mach_vm_size_t submap_size = size * 2;
mach_vm_address_t submap_start = start - submap_size / 2;
return test_single_submap_single_entry_common(
checker_list, submap_start, submap_size);
}
static test_result_t
test_single_submap_single_entry_middle_pages(
checker_list_t *checker_list,
mach_vm_address_t start,
mach_vm_size_t size)
{
/* tested range excludes the first 1/4 and last 1/4 of the real entry */
mach_vm_size_t submap_size = size * 2;
mach_vm_address_t submap_start = start - submap_size / 4;
return test_single_submap_single_entry_common(
checker_list, submap_start, submap_size);
}
static test_result_t
test_single_submap_oversize_entry_common(
checker_list_t *checker_list,
mach_vm_address_t parent_start,
mach_vm_size_t parent_size,
mach_vm_address_t parent_offset,
mach_vm_size_t submap_size)
{
vm_region_submap_info_data_64_t parent_info, content_info;
vm_entry_checker_t *submap_parent = checker_list_nth(checker_list, 0);
assert_submap_checker_and_entry(submap_parent, parent_start, parent_size, &parent_info);
assert(submap_parent->object_offset == parent_offset);
assert(parent_info.offset == parent_offset);
checker_list_t *submap_checkers DEFER_UNSLIDE =
checker_get_and_slide_submap_checkers(submap_parent);
/*
* Actual entry in submap is clamped to the parent map submap view
* by vm_region. Checker for that entry is unchanged.
*/
vm_entry_checker_t *submap_content = checker_list_nth(submap_checkers, 0);
assert_allocation_checker(submap_content, parent_start - parent_offset, submap_size);
assert(submap_content->submap_depth == 1);
assert_allocation_entry(parent_start, parent_size, 1 /* submap_depth */, &content_info);
assert(submap_content->object_offset == 0);
assert(content_info.offset == 0);
return TestSucceeded;
}
static test_result_t
test_single_submap_oversize_entry_at_start(
checker_list_t *checker_list,
mach_vm_address_t start,
mach_vm_size_t size)
{
/*
* parent map: [start, start+size]
* submap: [0 (size) size*2]
*/
return test_single_submap_oversize_entry_common(checker_list,
start, size,
size /* parent_offset */, size * 2 /* submap_size */);
}
static test_result_t
test_single_submap_oversize_entry_at_end(
checker_list_t *checker_list,
mach_vm_address_t start,
mach_vm_size_t size)
{
/*
* parent map: [start, start+size]
* submap: [0 (size) size*2]
*/
return test_single_submap_oversize_entry_common(checker_list,
start, size,
0 /* parent_offset */, size * 2 /* submap_size */);
}
static test_result_t
test_single_submap_oversize_entry_at_both(
checker_list_t *checker_list,
mach_vm_address_t start,
mach_vm_size_t size)
{
/*
* parent map: [start, start+size]
* submap: [0 (size / 2) size*2]
*/
return test_single_submap_oversize_entry_common(checker_list,
start, size,
size / 2 /* parent_offset */, size * 2 /* submap_size */);
}
static test_result_t
test_submap_before_allocation_common(
checker_list_t *checker_list,
mach_vm_address_t start,
mach_vm_size_t size,
int submap_protection)
{
vm_region_submap_info_data_64_t submap_parent_info;
vm_entry_checker_t *submap_parent = checker_list_nth(checker_list, 0);
assert_submap_checker_and_entry(submap_parent,
start, size / 2, &submap_parent_info);
vm_region_submap_info_data_64_t allocation_info;
vm_entry_checker_t *allocation = checker_list_nth(checker_list, 1);
assert_allocation_checker_and_entry(allocation,
start + size / 2, size / 2, &allocation_info);
checker_list_t *submap_checkers DEFER_UNSLIDE =
checker_get_and_slide_submap_checkers(submap_parent);
vm_region_submap_info_data_64_t submap_content_info;
vm_entry_checker_t *submap_content = checker_list_nth(submap_checkers, 0);
assert_allocation_checker(submap_content, start, size / 2);
assert_allocation_entry(start, size / 2, 1 /* submap_depth */, &submap_content_info);
assert_checker_and_entry_protection_equals(submap_content, &submap_content_info,
submap_protection, submap_protection);
return TestSucceeded;
}
static test_result_t
test_submap_before_allocation(
checker_list_t *checker_list,
mach_vm_address_t start,
mach_vm_size_t size)
{
return test_submap_before_allocation_common(checker_list,
start, size, VM_PROT_READ | VM_PROT_WRITE);
}
static test_result_t
test_submap_before_allocation_ro(
checker_list_t *checker_list,
mach_vm_address_t start,
mach_vm_size_t size)
{
return test_submap_before_allocation_common(checker_list,
start, size, VM_PROT_READ);
}
static test_result_t
test_submap_after_allocation_common(
checker_list_t *checker_list,
mach_vm_address_t start,
mach_vm_size_t size,
int submap_protection)
{
vm_region_submap_info_data_64_t allocation_info;
vm_entry_checker_t *allocation = checker_list_nth(checker_list, 0);
assert_allocation_checker_and_entry(allocation,
start, size / 2, &allocation_info);
vm_region_submap_info_data_64_t submap_parent_info;
vm_entry_checker_t *submap_parent = checker_list_nth(checker_list, 1);
assert_submap_checker_and_entry(submap_parent,
start + size / 2, size / 2, &submap_parent_info);
checker_list_t *submap_checkers DEFER_UNSLIDE =
checker_get_and_slide_submap_checkers(submap_parent);
vm_region_submap_info_data_64_t submap_content_info;
vm_entry_checker_t *submap_content = checker_list_nth(submap_checkers, 0);
assert_allocation_checker(submap_content, start + size / 2, size / 2);
assert_allocation_entry(start + size / 2, size / 2, 1 /* submap_depth */, &submap_content_info);
assert_checker_and_entry_protection_equals(submap_content, &submap_content_info,
submap_protection, submap_protection);
return TestSucceeded;
}
static test_result_t
test_submap_after_allocation(
checker_list_t *checker_list,
mach_vm_address_t start,
mach_vm_size_t size)
{
return test_submap_after_allocation_common(checker_list,
start, size, VM_PROT_READ | VM_PROT_WRITE);
}
static test_result_t
test_submap_after_allocation_ro(
checker_list_t *checker_list,
mach_vm_address_t start,
mach_vm_size_t size)
{
return test_submap_after_allocation_common(checker_list,
start, size, VM_PROT_READ);
}
static test_result_t
test_submap_before_hole_common(
checker_list_t *checker_list,
mach_vm_address_t start,
mach_vm_size_t size,
int submap_protection)
{
vm_region_submap_info_data_64_t submap_parent_info;
vm_entry_checker_t *submap_parent = checker_list_nth(checker_list, 0);
assert_submap_checker_and_entry(submap_parent,
start, size / 2, &submap_parent_info);
vm_entry_checker_t *hole = checker_list_nth(checker_list, 1);
assert_hole_checker_and_entry(hole,
start + size / 2, size / 2);
checker_list_t *submap_checkers DEFER_UNSLIDE =
checker_get_and_slide_submap_checkers(submap_parent);
vm_region_submap_info_data_64_t submap_content_info;
vm_entry_checker_t *submap_content = checker_list_nth(submap_checkers, 0);
assert_allocation_checker(submap_content, start, size / 2);
assert_allocation_entry(start, size / 2, 1 /* submap_depth */, &submap_content_info);
assert_checker_and_entry_protection_equals(submap_content, &submap_content_info,
submap_protection, submap_protection);
return TestSucceeded;
}
static test_result_t
test_submap_before_hole(
checker_list_t *checker_list,
mach_vm_address_t start,
mach_vm_size_t size)
{
return test_submap_before_hole_common(checker_list,
start, size, VM_PROT_READ | VM_PROT_WRITE);
}
static test_result_t
test_submap_before_hole_ro(
checker_list_t *checker_list,
mach_vm_address_t start,
mach_vm_size_t size)
{
return test_submap_before_hole_common(checker_list,
start, size, VM_PROT_READ);
}
static test_result_t
test_submap_after_hole_common(
checker_list_t *checker_list,
mach_vm_address_t start,
mach_vm_size_t size,
int submap_protection)
{
vm_entry_checker_t *hole = checker_list_nth(checker_list, 0);
assert_hole_checker_and_entry(hole,
start, size / 2);
vm_region_submap_info_data_64_t submap_parent_info;
vm_entry_checker_t *submap_parent = checker_list_nth(checker_list, 1);
assert_submap_checker_and_entry(submap_parent,
start + size / 2, size / 2, &submap_parent_info);
checker_list_t *submap_checkers DEFER_UNSLIDE =
checker_get_and_slide_submap_checkers(submap_parent);
vm_region_submap_info_data_64_t submap_content_info;
vm_entry_checker_t *submap_content = checker_list_nth(submap_checkers, 0);
assert_allocation_checker(submap_content, start + size / 2, size / 2);
assert_allocation_entry(start + size / 2, size / 2, 1 /* submap_depth */, &submap_content_info);
assert_checker_and_entry_protection_equals(submap_content, &submap_content_info,
submap_protection, submap_protection);
return TestSucceeded;
}
static test_result_t
test_submap_after_hole(
checker_list_t *checker_list,
mach_vm_address_t start,
mach_vm_size_t size)
{
return test_submap_after_hole_common(checker_list,
start, size, VM_PROT_READ | VM_PROT_WRITE);
}
static test_result_t
test_submap_after_hole_ro(
checker_list_t *checker_list,
mach_vm_address_t start,
mach_vm_size_t size)
{
return test_submap_after_hole_common(checker_list,
start, size, VM_PROT_READ);
}
/*
* Verify that the checker list consists of three entries,
* a submap mapping, an allocation, and a submap mapping,
* all of default size.
*/
static void
assert_submap_allocation_submap(
checker_list_t *checker_list,
mach_vm_address_t start,
mach_vm_size_t size)
{
vm_region_submap_info_data_64_t info;
vm_entry_checker_t *checker;
mach_vm_size_t offset;
assert(checker_range_count(checker_list->entries) == 3);
offset = DEFAULT_ENTRY_SIZE * 0;
checker = checker_list_nth(checker_list, 0);
assert_submap_checker_and_entry(checker,
start + offset, DEFAULT_ENTRY_SIZE, &info);
assert(checker->object_offset == offset);
assert(info.offset == offset);
offset = DEFAULT_ENTRY_SIZE * 1;
checker = checker_list_nth(checker_list, 1);
assert_allocation_checker_and_entry(checker,
start + offset, DEFAULT_ENTRY_SIZE, &info);
offset = DEFAULT_ENTRY_SIZE * 2;
checker = checker_list_nth(checker_list, 2);
assert_submap_checker_and_entry(checker,
start + offset, DEFAULT_ENTRY_SIZE, &info);
assert(checker->object_offset == offset);
assert(info.offset == offset);
offset = DEFAULT_ENTRY_SIZE * 3;
assert(size == offset);
}
static test_result_t
test_submap_allocation_submap_one_entry_common(
checker_list_t *checker_list,
mach_vm_address_t start,
mach_vm_size_t size,
int submap_protection)
{
/* parent map is submap - allocation - submap */
assert_submap_allocation_submap(checker_list, start, size);
/* submap is one allocation entry */
checker_list_t *submap_checkers DEFER_UNSLIDE =
checker_get_and_slide_submap_checkers(checker_list_nth(checker_list, 0));
assert(checker_range_count(submap_checkers->entries) == 1);
vm_entry_checker_t *submap_content = checker_list_nth(submap_checkers, 0);
assert_allocation_checker(submap_content, start, size);
assert(submap_content->protection == submap_protection);
assert(submap_content->max_protection == submap_protection);
return TestSucceeded;
}
static test_result_t
test_submap_allocation_submap_one_entry(
checker_list_t *checker_list,
mach_vm_address_t start,
mach_vm_size_t size)
{
return test_submap_allocation_submap_one_entry_common(checker_list,
start, size, VM_PROT_READ | VM_PROT_WRITE);
}
static test_result_t
test_submap_allocation_submap_one_entry_ro(
checker_list_t *checker_list,
mach_vm_address_t start,
mach_vm_size_t size)
{
return test_submap_allocation_submap_one_entry_common(checker_list,
start, size, VM_PROT_READ);
}
static test_result_t
test_submap_allocation_submap_two_entries_common(
checker_list_t *checker_list,
mach_vm_address_t start,
mach_vm_size_t size,
int submap_protection)
{
/* parent map is submap - allocation - submap */
assert_submap_allocation_submap(checker_list, start, size);
/* submap is two allocation entries */
checker_list_t *submap_checkers DEFER_UNSLIDE =
checker_get_and_slide_submap_checkers(checker_list_nth(checker_list, 0));
assert(checker_range_count(submap_checkers->entries) == 2);
vm_entry_checker_t *submap_content = checker_list_nth(submap_checkers, 0);
assert_allocation_checker(submap_content, start, size / 2);
assert(submap_content->protection == submap_protection);
assert(submap_content->max_protection == submap_protection);
submap_content = checker_list_nth(submap_checkers, 1);
assert_allocation_checker(submap_content, start + size / 2, size / 2);
assert(submap_content->protection == submap_protection);
assert(submap_content->max_protection == submap_protection);
return TestSucceeded;
}
static test_result_t
test_submap_allocation_submap_two_entries(
checker_list_t *checker_list,
mach_vm_address_t start,
mach_vm_size_t size)
{
return test_submap_allocation_submap_two_entries_common(checker_list,
start, size, VM_PROT_READ | VM_PROT_WRITE);
}
static test_result_t
test_submap_allocation_submap_two_entries_ro(
checker_list_t *checker_list,
mach_vm_address_t start,
mach_vm_size_t size)
{
return test_submap_allocation_submap_two_entries_common(checker_list,
start, size, VM_PROT_READ);
}
static test_result_t
test_submap_allocation_submap_three_entries_common(
checker_list_t *checker_list,
mach_vm_address_t start,
mach_vm_size_t size,
int submap_protection)
{
/* parent map is submap - allocation - submap */
assert_submap_allocation_submap(checker_list, start, size);
/* submap is three allocation entries */
checker_list_t *submap_checkers DEFER_UNSLIDE =
checker_get_and_slide_submap_checkers(checker_list_nth(checker_list, 0));
assert(checker_range_count(submap_checkers->entries) == 3);
vm_entry_checker_t *submap_content = checker_list_nth(submap_checkers, 0);
assert_allocation_checker(submap_content, start, size / 3);
assert(submap_content->protection == submap_protection);
assert(submap_content->max_protection == submap_protection);
submap_content = checker_list_nth(submap_checkers, 1);
assert_allocation_checker(submap_content, start + size / 3, size / 3);
assert(submap_content->protection == submap_protection);
assert(submap_content->max_protection == submap_protection);
submap_content = checker_list_nth(submap_checkers, 2);
assert_allocation_checker(submap_content, start + size / 3 * 2, size / 3);
assert(submap_content->protection == submap_protection);
assert(submap_content->max_protection == submap_protection);
return TestSucceeded;
}
static test_result_t
test_submap_allocation_submap_three_entries(
checker_list_t *checker_list,
mach_vm_address_t start,
mach_vm_size_t size)
{
return test_submap_allocation_submap_three_entries_common(checker_list,
start, size, VM_PROT_READ | VM_PROT_WRITE);
}
static test_result_t
test_submap_allocation_submap_three_entries_ro(
checker_list_t *checker_list,
mach_vm_address_t start,
mach_vm_size_t size)
{
return test_submap_allocation_submap_three_entries_common(checker_list,
start, size, VM_PROT_READ);
}
static void
assert_protection(
mach_vm_address_t address,
vm_prot_t prot,
bool check_max,
uint32_t submap_depth)
{
mach_vm_address_t info_address = address;
mach_vm_size_t info_size;
vm_region_submap_info_data_64_t info;
assert(get_info_for_address(&info_address, &info_size, &info, submap_depth));
assert(info_address == address);
if (check_max) {
T_QUIET; T_ASSERT_EQ(prot, info.max_protection, "entry max protection");
} else {
T_QUIET; T_ASSERT_EQ(prot, info.protection, "entry protection");
}
}
static test_result_t
test_protection_single_common(
checker_list_t *checker_list,
mach_vm_address_t address,
vm_prot_t prot, vm_prot_t max)
{
vm_entry_checker_t *checker =
checker_list_find_allocation(checker_list, address);
T_QUIET; T_ASSERT_NOTNULL(checker, "checker");
T_QUIET; T_ASSERT_EQ(checker->protection, prot, "checker protection");
T_QUIET; T_ASSERT_EQ(checker->max_protection, max, "checker max protection");
assert_protection(address, prot, false /* check max */, 0 /* submap depth */);
assert_protection(address, max, true /* check max */, 0 /* submap depth */);
return TestSucceeded;
}
static test_result_t
test_protection_pair_common(
checker_list_t *checker_list,
mach_vm_address_t address,
vm_prot_t left_prot,
vm_prot_t right_prot)
{
vm_entry_checker_t *left_checker =
checker_list_find_allocation(checker_list, address);
vm_entry_checker_t *right_checker = left_checker->next;
T_QUIET; T_ASSERT_NOTNULL(left_checker, "checker");
T_QUIET; T_ASSERT_EQ(left_checker->protection, left_prot, "left entry protection");
T_QUIET; T_ASSERT_EQ(right_checker->protection, right_prot, "right entry protection");
assert_protection(left_checker->address, left_prot, false /* check max */, 0 /* submap depth */);
assert_protection(right_checker->address, right_prot, false /* check max */, 0 /* submap depth */);
return TestSucceeded;
}
static test_result_t
test_protection_single_000_000(
checker_list_t *checker_list,
mach_vm_address_t start,
mach_vm_size_t size __unused)
{
return test_protection_single_common(
checker_list, start, VM_PROT_NONE, VM_PROT_NONE);
}
static test_result_t
test_protection_single_000_r00(
checker_list_t *checker_list,
mach_vm_address_t start,
mach_vm_size_t size __unused)
{
return test_protection_single_common(
checker_list, start, VM_PROT_NONE, VM_PROT_READ);
}
static test_result_t
test_protection_single_000_0w0(
checker_list_t *checker_list,
mach_vm_address_t start,
mach_vm_size_t size __unused)
{
return test_protection_single_common(
checker_list, start, VM_PROT_NONE, VM_PROT_WRITE);
}
static test_result_t
test_protection_single_000_rw0(
checker_list_t *checker_list,
mach_vm_address_t start,
mach_vm_size_t size __unused)
{
return test_protection_single_common(
checker_list, start, VM_PROT_NONE, VM_PROT_READ | VM_PROT_WRITE);
}
static test_result_t
test_protection_single_r00_r00(
checker_list_t *checker_list,
mach_vm_address_t start,
mach_vm_size_t size __unused)
{
return test_protection_single_common(
checker_list, start, VM_PROT_READ, VM_PROT_READ);
}
static test_result_t
test_protection_single_r00_rw0(
checker_list_t *checker_list,
mach_vm_address_t start,
mach_vm_size_t size __unused)
{
return test_protection_single_common(
checker_list, start, VM_PROT_READ, VM_PROT_READ | VM_PROT_WRITE);
}
static test_result_t
test_protection_single_0w0_0w0(
checker_list_t *checker_list,
mach_vm_address_t start,
mach_vm_size_t size __unused)
{
return test_protection_single_common(
checker_list, start, VM_PROT_WRITE, VM_PROT_WRITE);
}
static test_result_t
test_protection_single_0w0_rw0(
checker_list_t *checker_list,
mach_vm_address_t start,
mach_vm_size_t size __unused)
{
return test_protection_single_common(
checker_list, start, VM_PROT_WRITE, VM_PROT_READ | VM_PROT_WRITE);
}
static test_result_t
test_protection_single_rw0_rw0(
checker_list_t *checker_list,
mach_vm_address_t start,
mach_vm_size_t size __unused)
{
return test_protection_single_common(
checker_list, start, VM_PROT_READ | VM_PROT_WRITE, VM_PROT_READ | VM_PROT_WRITE);
}
static test_result_t
test_protection_pair_000_000(
checker_list_t *checker_list,
mach_vm_address_t start,
mach_vm_size_t size __unused)
{
return test_protection_pair_common(
checker_list, start, VM_PROT_NONE, VM_PROT_NONE);
}
static test_result_t
test_protection_pair_000_r00(
checker_list_t *checker_list,
mach_vm_address_t start,
mach_vm_size_t size __unused)
{
return test_protection_pair_common(
checker_list, start, VM_PROT_NONE, VM_PROT_READ);
}
static test_result_t
test_protection_pair_000_0w0(
checker_list_t *checker_list,
mach_vm_address_t start,
mach_vm_size_t size __unused)
{
return test_protection_pair_common(
checker_list, start, VM_PROT_NONE, VM_PROT_WRITE);
}
static test_result_t
test_protection_pair_000_rw0(
checker_list_t *checker_list,
mach_vm_address_t start,
mach_vm_size_t size __unused)
{
return test_protection_pair_common(
checker_list, start, VM_PROT_NONE, VM_PROT_READ | VM_PROT_WRITE);
}
static test_result_t
test_protection_pair_r00_000(
checker_list_t *checker_list,
mach_vm_address_t start,
mach_vm_size_t size __unused)
{
return test_protection_pair_common(
checker_list, start, VM_PROT_READ, VM_PROT_NONE);
}
static test_result_t
test_protection_pair_r00_r00(
checker_list_t *checker_list,
mach_vm_address_t start,
mach_vm_size_t size __unused)
{
return test_protection_pair_common(
checker_list, start, VM_PROT_READ, VM_PROT_READ);
}
static test_result_t
test_protection_pair_r00_0w0(
checker_list_t *checker_list,
mach_vm_address_t start,
mach_vm_size_t size __unused)
{
return test_protection_pair_common(
checker_list, start, VM_PROT_READ, VM_PROT_WRITE);
}
static test_result_t
test_protection_pair_r00_rw0(
checker_list_t *checker_list,
mach_vm_address_t start,
mach_vm_size_t size __unused)
{
return test_protection_pair_common(
checker_list, start, VM_PROT_READ, VM_PROT_READ | VM_PROT_WRITE);
}
static test_result_t
test_protection_pair_0w0_000(
checker_list_t *checker_list,
mach_vm_address_t start,
mach_vm_size_t size __unused)
{
return test_protection_pair_common(
checker_list, start, VM_PROT_WRITE, VM_PROT_NONE);
}
static test_result_t
test_protection_pair_0w0_r00(
checker_list_t *checker_list,
mach_vm_address_t start,
mach_vm_size_t size __unused)
{
return test_protection_pair_common(
checker_list, start, VM_PROT_WRITE, VM_PROT_READ);
}
static test_result_t
test_protection_pair_0w0_0w0(
checker_list_t *checker_list,
mach_vm_address_t start,
mach_vm_size_t size __unused)
{
return test_protection_pair_common(
checker_list, start, VM_PROT_WRITE, VM_PROT_WRITE);
}
static test_result_t
test_protection_pair_0w0_rw0(
checker_list_t *checker_list,
mach_vm_address_t start,
mach_vm_size_t size __unused)
{
return test_protection_pair_common(
checker_list, start, VM_PROT_WRITE, VM_PROT_READ | VM_PROT_WRITE);
}
static test_result_t
test_protection_pair_rw0_000(
checker_list_t *checker_list,
mach_vm_address_t start,
mach_vm_size_t size __unused)
{
return test_protection_pair_common(
checker_list, start, VM_PROT_READ | VM_PROT_WRITE, VM_PROT_NONE);
}
static test_result_t
test_protection_pair_rw0_r00(
checker_list_t *checker_list,
mach_vm_address_t start,
mach_vm_size_t size __unused)
{
return test_protection_pair_common(
checker_list, start, VM_PROT_READ | VM_PROT_WRITE, VM_PROT_READ);
}
static test_result_t
test_protection_pair_rw0_0w0(
checker_list_t *checker_list,
mach_vm_address_t start,
mach_vm_size_t size __unused)
{
return test_protection_pair_common(
checker_list, start, VM_PROT_READ | VM_PROT_WRITE, VM_PROT_WRITE);
}
static test_result_t
test_protection_pair_rw0_rw0(
checker_list_t *checker_list,
mach_vm_address_t start,
mach_vm_size_t size __unused)
{
return test_protection_pair_common(
checker_list, start, VM_PROT_READ | VM_PROT_WRITE, VM_PROT_READ | VM_PROT_WRITE);
}
T_DECL(test_vm_configurator,
"spot-check VM states generated by vm configurator")
{
vm_tests_t tests = {
.single_entry_1 = test_single_entry_1,
.single_entry_2 = test_single_entry_2,
.single_entry_3 = test_single_entry_3,
.single_entry_4 = test_single_entry_4,
.multiple_entries_1 = test_multiple_entries_1,
.multiple_entries_2 = test_multiple_entries_2,
.multiple_entries_3 = test_multiple_entries_3,
.multiple_entries_4 = test_multiple_entries_4,
.multiple_entries_5 = test_multiple_entries_5,
.multiple_entries_6 = test_multiple_entries_6,
.some_holes_1 = test_some_holes_1,
.some_holes_2 = test_some_holes_2,
.some_holes_3 = test_some_holes_3,
.some_holes_4 = test_some_holes_4,
.some_holes_5 = test_some_holes_5,
.some_holes_6 = test_some_holes_6,
.some_holes_7 = test_some_holes_7,
.some_holes_8 = test_some_holes_8,
.some_holes_9 = test_some_holes_9,
.some_holes_10 = test_some_holes_10,
.some_holes_11 = test_some_holes_11,
.some_holes_12 = test_some_holes_12,
.all_holes_1 = test_all_holes_1,
.all_holes_2 = test_all_holes_2,
.all_holes_3 = test_all_holes_3,
.all_holes_4 = test_all_holes_4,
.null_entry = test_null_entry,
.nonresident_entry = test_nonresident_entry,
.resident_entry = test_resident_entry,
.shared_entry = test_shared_entry,
.shared_entry_discontiguous = test_shared_entry_discontiguous,
.shared_entry_partial = test_shared_entry_partial,
.shared_entry_pairs = test_shared_entry_pairs,
.shared_entry_x1000 = test_shared_entry_x1000,
.cow_entry = test_cow_entry,
.cow_unreferenced = test_cow_unreferenced,
.cow_nocow = test_cow_nocow,
.nocow_cow = test_nocow_cow,
.cow_unreadable = test_cow_unreadable,
.cow_unwriteable = test_cow_unwriteable,
.permanent_entry = test_permanent_entry,
.permanent_before_permanent = test_permanent_before_permanent,
.permanent_before_allocation = test_permanent_before_allocation,
.permanent_before_allocation_2 = test_permanent_before_allocation_2,
.permanent_before_hole = test_permanent_before_hole,
.permanent_after_allocation = test_permanent_after_allocation,
.permanent_after_hole = test_permanent_after_hole,
.single_submap_single_entry = test_single_submap_single_entry,
.single_submap_single_entry_first_pages = test_single_submap_single_entry_first_pages,
.single_submap_single_entry_last_pages = test_single_submap_single_entry_last_pages,
.single_submap_single_entry_middle_pages = test_single_submap_single_entry_middle_pages,
.single_submap_oversize_entry_at_start = test_single_submap_oversize_entry_at_start,
.single_submap_oversize_entry_at_end = test_single_submap_oversize_entry_at_end,
.single_submap_oversize_entry_at_both = test_single_submap_oversize_entry_at_both,
.submap_before_allocation = test_submap_before_allocation,
.submap_after_allocation = test_submap_after_allocation,
.submap_before_hole = test_submap_before_hole,
.submap_after_hole = test_submap_after_hole,
.submap_allocation_submap_one_entry = test_submap_allocation_submap_one_entry,
.submap_allocation_submap_two_entries = test_submap_allocation_submap_two_entries,
.submap_allocation_submap_three_entries = test_submap_allocation_submap_three_entries,
.submap_before_allocation_ro = test_submap_before_allocation_ro,
.submap_after_allocation_ro = test_submap_after_allocation_ro,
.submap_before_hole_ro = test_submap_before_hole_ro,
.submap_after_hole_ro = test_submap_after_hole_ro,
.submap_allocation_submap_one_entry_ro = test_submap_allocation_submap_one_entry_ro,
.submap_allocation_submap_two_entries_ro = test_submap_allocation_submap_two_entries_ro,
.submap_allocation_submap_three_entries_ro = test_submap_allocation_submap_three_entries_ro,
.protection_single_000_000 = test_protection_single_000_000,
.protection_single_000_r00 = test_protection_single_000_r00,
.protection_single_000_0w0 = test_protection_single_000_0w0,
.protection_single_000_rw0 = test_protection_single_000_rw0,
.protection_single_r00_r00 = test_protection_single_r00_r00,
.protection_single_r00_rw0 = test_protection_single_r00_rw0,
.protection_single_0w0_0w0 = test_protection_single_0w0_0w0,
.protection_single_0w0_rw0 = test_protection_single_0w0_rw0,
.protection_single_rw0_rw0 = test_protection_single_rw0_rw0,
.protection_pairs_000_000 = test_protection_pair_000_000,
.protection_pairs_000_r00 = test_protection_pair_000_r00,
.protection_pairs_000_0w0 = test_protection_pair_000_0w0,
.protection_pairs_000_rw0 = test_protection_pair_000_rw0,
.protection_pairs_r00_000 = test_protection_pair_r00_000,
.protection_pairs_r00_r00 = test_protection_pair_r00_r00,
.protection_pairs_r00_0w0 = test_protection_pair_r00_0w0,
.protection_pairs_r00_rw0 = test_protection_pair_r00_rw0,
.protection_pairs_0w0_000 = test_protection_pair_0w0_000,
.protection_pairs_0w0_r00 = test_protection_pair_0w0_r00,
.protection_pairs_0w0_0w0 = test_protection_pair_0w0_0w0,
.protection_pairs_0w0_rw0 = test_protection_pair_0w0_rw0,
.protection_pairs_rw0_000 = test_protection_pair_rw0_000,
.protection_pairs_rw0_r00 = test_protection_pair_rw0_r00,
.protection_pairs_rw0_0w0 = test_protection_pair_rw0_0w0,
.protection_pairs_rw0_rw0 = test_protection_pair_rw0_rw0,
};
run_vm_tests("test_vm_configurator", __FILE__, &tests, argc, argv);
}