diff options
Diffstat (limited to 'libipt/test/src')
25 files changed, 16620 insertions, 0 deletions
diff --git a/libipt/test/src/ptunit-asid.c b/libipt/test/src/ptunit-asid.c new file mode 100644 index 0000000000000..b8983939b526f --- /dev/null +++ b/libipt/test/src/ptunit-asid.c @@ -0,0 +1,425 @@ +/* + * Copyright (c) 2014-2019, Intel Corporation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of Intel Corporation nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "ptunit.h" + +#include "pt_asid.h" + +#include "intel-pt.h" + +#include <stddef.h> + + +static struct ptunit_result from_user_null(void) +{ + struct pt_asid user; + int errcode; + + pt_asid_init(&user); + + errcode = pt_asid_from_user(NULL, NULL); + ptu_int_eq(errcode, -pte_internal); + + errcode = pt_asid_from_user(NULL, &user); + ptu_int_eq(errcode, -pte_internal); + + return ptu_passed(); +} + +static struct ptunit_result from_user_default(void) +{ + struct pt_asid asid; + int errcode; + + errcode = pt_asid_from_user(&asid, NULL); + ptu_int_eq(errcode, 0); + ptu_uint_eq(asid.size, sizeof(asid)); + ptu_uint_eq(asid.cr3, pt_asid_no_cr3); + ptu_uint_eq(asid.vmcs, pt_asid_no_vmcs); + + return ptu_passed(); +} + +static struct ptunit_result from_user_small(void) +{ + struct pt_asid asid, user; + int errcode; + + user.size = sizeof(user.size); + + errcode = pt_asid_from_user(&asid, &user); + ptu_int_eq(errcode, 0); + ptu_uint_eq(asid.size, sizeof(asid)); + ptu_uint_eq(asid.cr3, pt_asid_no_cr3); + ptu_uint_eq(asid.vmcs, pt_asid_no_vmcs); + + return ptu_passed(); +} + +static struct ptunit_result from_user_big(void) +{ + struct pt_asid asid, user; + int errcode; + + user.size = sizeof(user) + 4; + user.cr3 = 0x4200ull; + user.vmcs = 0x23000ull; + + errcode = pt_asid_from_user(&asid, &user); + ptu_int_eq(errcode, 0); + ptu_uint_eq(asid.size, sizeof(asid)); + ptu_uint_eq(asid.cr3, 0x4200ull); + ptu_uint_eq(asid.vmcs, 0x23000ull); + + return ptu_passed(); +} + +static struct ptunit_result from_user(void) +{ + struct pt_asid asid, user; + int errcode; + + user.size = sizeof(user); + user.cr3 = 0x4200ull; + user.vmcs = 0x23000ull; + + errcode = pt_asid_from_user(&asid, &user); + ptu_int_eq(errcode, 0); + ptu_uint_eq(asid.size, sizeof(asid)); + ptu_uint_eq(asid.cr3, 0x4200ull); + ptu_uint_eq(asid.vmcs, 0x23000ull); + + return ptu_passed(); +} + +static struct ptunit_result from_user_cr3(void) +{ + struct pt_asid asid, user; + int errcode; + + user.size = offsetof(struct pt_asid, vmcs); + user.cr3 = 0x4200ull; + user.vmcs = 0x23000ull; + + errcode = pt_asid_from_user(&asid, &user); + ptu_int_eq(errcode, 0); + ptu_uint_eq(asid.size, sizeof(asid)); + ptu_uint_eq(asid.cr3, 0x4200ull); + ptu_uint_eq(asid.vmcs, pt_asid_no_vmcs); + + return ptu_passed(); +} + +static struct ptunit_result to_user_null(void) +{ + struct pt_asid asid; + int errcode; + + pt_asid_init(&asid); + + errcode = pt_asid_to_user(NULL, NULL, sizeof(asid)); + ptu_int_eq(errcode, -pte_internal); + + errcode = pt_asid_to_user(NULL, &asid, sizeof(asid)); + ptu_int_eq(errcode, -pte_internal); + + return ptu_passed(); +} + +static struct ptunit_result to_user_too_small(void) +{ + struct pt_asid asid, user; + int errcode; + + pt_asid_init(&asid); + + errcode = pt_asid_to_user(&user, &asid, 0); + ptu_int_eq(errcode, -pte_invalid); + + errcode = pt_asid_to_user(&user, &asid, sizeof(user.size) - 1); + ptu_int_eq(errcode, -pte_invalid); + + return ptu_passed(); +} + +static struct ptunit_result to_user_small(void) +{ + struct pt_asid asid, user; + int errcode; + + memset(&user, 0xcc, sizeof(user)); + pt_asid_init(&asid); + + errcode = pt_asid_to_user(&user, &asid, sizeof(user.size)); + ptu_int_eq(errcode, 0); + ptu_uint_eq(user.size, sizeof(user.size)); + ptu_uint_eq(user.cr3, 0xccccccccccccccccull); + ptu_uint_eq(user.vmcs, 0xccccccccccccccccull); + + return ptu_passed(); +} + +static struct ptunit_result to_user_big(void) +{ + struct pt_asid asid, user; + int errcode; + + memset(&user, 0xcc, sizeof(user)); + pt_asid_init(&asid); + asid.cr3 = 0x4200ull; + asid.vmcs = 0x23000ull; + + errcode = pt_asid_to_user(&user, &asid, sizeof(user) + 8); + ptu_int_eq(errcode, 0); + ptu_uint_eq(user.size, sizeof(asid)); + ptu_uint_eq(user.cr3, 0x4200ull); + ptu_uint_eq(user.vmcs, 0x23000ull); + + return ptu_passed(); +} + +static struct ptunit_result to_user(void) +{ + struct pt_asid asid, user; + int errcode; + + memset(&user, 0xcc, sizeof(user)); + pt_asid_init(&asid); + asid.cr3 = 0x4200ull; + asid.vmcs = 0x23000ull; + + errcode = pt_asid_to_user(&user, &asid, sizeof(user)); + ptu_int_eq(errcode, 0); + ptu_uint_eq(user.size, sizeof(asid)); + ptu_uint_eq(user.cr3, 0x4200ull); + ptu_uint_eq(user.vmcs, 0x23000ull); + + return ptu_passed(); +} + +static struct ptunit_result to_user_cr3(void) +{ + struct pt_asid asid, user; + int errcode; + + memset(&user, 0xcc, sizeof(user)); + pt_asid_init(&asid); + asid.cr3 = 0x4200ull; + + errcode = pt_asid_to_user(&user, &asid, offsetof(struct pt_asid, vmcs)); + ptu_int_eq(errcode, 0); + ptu_uint_eq(user.size, offsetof(struct pt_asid, vmcs)); + ptu_uint_eq(user.cr3, 0x4200ull); + ptu_uint_eq(user.vmcs, 0xccccccccccccccccull); + + return ptu_passed(); +} + +static struct ptunit_result match_null(void) +{ + struct pt_asid asid; + int errcode; + + pt_asid_init(&asid); + + errcode = pt_asid_match(NULL, NULL); + ptu_int_eq(errcode, -pte_internal); + + errcode = pt_asid_match(NULL, &asid); + ptu_int_eq(errcode, -pte_internal); + + errcode = pt_asid_match(&asid, NULL); + ptu_int_eq(errcode, -pte_internal); + + return ptu_passed(); +} + +static struct ptunit_result match_default(void) +{ + struct pt_asid lhs, rhs; + int errcode; + + pt_asid_init(&lhs); + pt_asid_init(&rhs); + + errcode = pt_asid_match(&lhs, &rhs); + ptu_int_eq(errcode, 1); + + lhs.cr3 = 0x2300ull; + lhs.vmcs = 0x42000ull; + + errcode = pt_asid_match(&lhs, &rhs); + ptu_int_eq(errcode, 1); + + errcode = pt_asid_match(&rhs, &lhs); + ptu_int_eq(errcode, 1); + + return ptu_passed(); +} + +static struct ptunit_result match_default_mixed(void) +{ + struct pt_asid lhs, rhs; + int errcode; + + pt_asid_init(&lhs); + pt_asid_init(&rhs); + + errcode = pt_asid_match(&lhs, &rhs); + ptu_int_eq(errcode, 1); + + lhs.cr3 = 0x2300ull; + rhs.vmcs = 0x42000ull; + + errcode = pt_asid_match(&lhs, &rhs); + ptu_int_eq(errcode, 1); + + errcode = pt_asid_match(&rhs, &lhs); + ptu_int_eq(errcode, 1); + + return ptu_passed(); +} + +static struct ptunit_result match_cr3(void) +{ + struct pt_asid lhs, rhs; + int errcode; + + pt_asid_init(&lhs); + pt_asid_init(&rhs); + + lhs.cr3 = 0x2300ull; + rhs.cr3 = 0x2300ull; + + errcode = pt_asid_match(&lhs, &rhs); + ptu_int_eq(errcode, 1); + + return ptu_passed(); +} + +static struct ptunit_result match_vmcs(void) +{ + struct pt_asid lhs, rhs; + int errcode; + + pt_asid_init(&lhs); + pt_asid_init(&rhs); + + lhs.vmcs = 0x23000ull; + rhs.vmcs = 0x23000ull; + + errcode = pt_asid_match(&lhs, &rhs); + ptu_int_eq(errcode, 1); + + return ptu_passed(); +} + +static struct ptunit_result match(void) +{ + struct pt_asid lhs, rhs; + int errcode; + + pt_asid_init(&lhs); + pt_asid_init(&rhs); + + lhs.cr3 = 0x2300ull; + rhs.cr3 = 0x2300ull; + lhs.vmcs = 0x23000ull; + rhs.vmcs = 0x23000ull; + + errcode = pt_asid_match(&lhs, &rhs); + ptu_int_eq(errcode, 1); + + return ptu_passed(); +} + +static struct ptunit_result match_cr3_false(void) +{ + struct pt_asid lhs, rhs; + int errcode; + + pt_asid_init(&lhs); + pt_asid_init(&rhs); + + lhs.cr3 = 0x4200ull; + rhs.cr3 = 0x2300ull; + + errcode = pt_asid_match(&lhs, &rhs); + ptu_int_eq(errcode, 0); + + return ptu_passed(); +} + +static struct ptunit_result match_vmcs_false(void) +{ + struct pt_asid lhs, rhs; + int errcode; + + pt_asid_init(&lhs); + pt_asid_init(&rhs); + + lhs.vmcs = 0x42000ull; + rhs.vmcs = 0x23000ull; + + errcode = pt_asid_match(&lhs, &rhs); + ptu_int_eq(errcode, 0); + + return ptu_passed(); +} + +int main(int argc, char **argv) +{ + struct ptunit_suite suite; + + suite = ptunit_mk_suite(argc, argv); + + ptu_run(suite, from_user_null); + ptu_run(suite, from_user_default); + ptu_run(suite, from_user_small); + ptu_run(suite, from_user_big); + ptu_run(suite, from_user); + ptu_run(suite, from_user_cr3); + + ptu_run(suite, to_user_null); + ptu_run(suite, to_user_too_small); + ptu_run(suite, to_user_small); + ptu_run(suite, to_user_big); + ptu_run(suite, to_user); + ptu_run(suite, to_user_cr3); + + ptu_run(suite, match_null); + ptu_run(suite, match_default); + ptu_run(suite, match_default_mixed); + ptu_run(suite, match_cr3); + ptu_run(suite, match_vmcs); + ptu_run(suite, match); + ptu_run(suite, match_cr3_false); + ptu_run(suite, match_vmcs_false); + + return ptunit_report(&suite); +} diff --git a/libipt/test/src/ptunit-block_cache.c b/libipt/test/src/ptunit-block_cache.c new file mode 100644 index 0000000000000..906fe319996b3 --- /dev/null +++ b/libipt/test/src/ptunit-block_cache.c @@ -0,0 +1,370 @@ +/* + * Copyright (c) 2016-2019, Intel Corporation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of Intel Corporation nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "ptunit_threads.h" + +#include "pt_block_cache.h" + +#include <string.h> + + +/* A test fixture optionally providing a block cache and automatically freeing + * the cache. + */ +struct bcache_fixture { + /* Threading support. */ + struct ptunit_thrd_fixture thrd; + + /* The cache - it will be freed automatically. */ + struct pt_block_cache *bcache; + + /* The test fixture initialization and finalization functions. */ + struct ptunit_result (*init)(struct bcache_fixture *); + struct ptunit_result (*fini)(struct bcache_fixture *); +}; + +enum { + /* The number of entries in fixture-provided caches. */ + bfix_nentries = 0x10000, + +#if defined(FEATURE_THREADS) + + /* The number of additional threads to use for stress testing. */ + bfix_threads = 3, + +#endif /* defined(FEATURE_THREADS) */ + + /* The number of iterations in stress testing. */ + bfix_iterations = 0x10 +}; + +static struct ptunit_result cfix_init(struct bcache_fixture *bfix) +{ + ptu_test(ptunit_thrd_init, &bfix->thrd); + + bfix->bcache = NULL; + + return ptu_passed(); +} + +static struct ptunit_result bfix_init(struct bcache_fixture *bfix) +{ + ptu_test(cfix_init, bfix); + + bfix->bcache = pt_bcache_alloc(bfix_nentries); + ptu_ptr(bfix->bcache); + + return ptu_passed(); +} + +static struct ptunit_result bfix_fini(struct bcache_fixture *bfix) +{ + int thrd; + + ptu_test(ptunit_thrd_fini, &bfix->thrd); + + for (thrd = 0; thrd < bfix->thrd.nthreads; ++thrd) + ptu_int_eq(bfix->thrd.result[thrd], 0); + + pt_bcache_free(bfix->bcache); + + return ptu_passed(); +} + +static struct ptunit_result bcache_entry_size(void) +{ + ptu_uint_eq(sizeof(struct pt_bcache_entry), sizeof(uint32_t)); + + return ptu_passed(); +} + +static struct ptunit_result bcache_size(void) +{ + ptu_uint_le(sizeof(struct pt_block_cache), + 2 * sizeof(struct pt_bcache_entry)); + + return ptu_passed(); +} + +static struct ptunit_result free_null(void) +{ + pt_bcache_free(NULL); + + return ptu_passed(); +} + +static struct ptunit_result add_null(void) +{ + struct pt_bcache_entry bce; + int errcode; + + memset(&bce, 0, sizeof(bce)); + + errcode = pt_bcache_add(NULL, 0ull, bce); + ptu_int_eq(errcode, -pte_internal); + + return ptu_passed(); +} + +static struct ptunit_result lookup_null(void) +{ + struct pt_bcache_entry bce; + struct pt_block_cache bcache; + int errcode; + + errcode = pt_bcache_lookup(&bce, NULL, 0ull); + ptu_int_eq(errcode, -pte_internal); + + errcode = pt_bcache_lookup(NULL, &bcache, 0ull); + ptu_int_eq(errcode, -pte_internal); + + return ptu_passed(); +} + +static struct ptunit_result alloc(struct bcache_fixture *bfix) +{ + bfix->bcache = pt_bcache_alloc(0x10000ull); + ptu_ptr(bfix->bcache); + + return ptu_passed(); +} + +static struct ptunit_result alloc_min(struct bcache_fixture *bfix) +{ + bfix->bcache = pt_bcache_alloc(1ull); + ptu_ptr(bfix->bcache); + + return ptu_passed(); +} + +static struct ptunit_result alloc_too_big(struct bcache_fixture *bfix) +{ + bfix->bcache = pt_bcache_alloc(UINT32_MAX + 1ull); + ptu_null(bfix->bcache); + + return ptu_passed(); +} + +static struct ptunit_result alloc_zero(struct bcache_fixture *bfix) +{ + bfix->bcache = pt_bcache_alloc(0ull); + ptu_null(bfix->bcache); + + return ptu_passed(); +} + +static struct ptunit_result initially_empty(struct bcache_fixture *bfix) +{ + uint64_t index; + + for (index = 0; index < bfix_nentries; ++index) { + struct pt_bcache_entry bce; + int status; + + memset(&bce, 0xff, sizeof(bce)); + + status = pt_bcache_lookup(&bce, bfix->bcache, index); + ptu_int_eq(status, 0); + + status = pt_bce_is_valid(bce); + ptu_int_eq(status, 0); + } + + return ptu_passed(); +} + +static struct ptunit_result add_bad_index(struct bcache_fixture *bfix) +{ + struct pt_bcache_entry bce; + int errcode; + + memset(&bce, 0, sizeof(bce)); + + errcode = pt_bcache_add(bfix->bcache, bfix_nentries, bce); + ptu_int_eq(errcode, -pte_internal); + + return ptu_passed(); +} + +static struct ptunit_result lookup_bad_index(struct bcache_fixture *bfix) +{ + struct pt_bcache_entry bce; + int errcode; + + errcode = pt_bcache_lookup(&bce, bfix->bcache, bfix_nentries); + ptu_int_eq(errcode, -pte_internal); + + return ptu_passed(); +} + +static struct ptunit_result add(struct bcache_fixture *bfix, uint64_t index) +{ + struct pt_bcache_entry bce, exp; + int errcode; + + memset(&bce, 0xff, sizeof(bce)); + memset(&exp, 0x00, sizeof(exp)); + + exp.ninsn = 1; + exp.displacement = 7; + exp.mode = ptem_64bit; + exp.qualifier = ptbq_decode; + exp.isize = 7; + + errcode = pt_bcache_add(bfix->bcache, index, exp); + ptu_int_eq(errcode, 0); + + errcode = pt_bcache_lookup(&bce, bfix->bcache, index); + ptu_int_eq(errcode, 0); + + ptu_uint_eq(bce.ninsn, exp.ninsn); + ptu_int_eq(bce.displacement, exp.displacement); + ptu_uint_eq(pt_bce_exec_mode(bce), pt_bce_exec_mode(exp)); + ptu_uint_eq(pt_bce_qualifier(bce), pt_bce_qualifier(exp)); + ptu_uint_eq(bce.isize, exp.isize); + + return ptu_passed(); +} + +static int worker(void *arg) +{ + struct pt_bcache_entry exp; + struct pt_block_cache *bcache; + uint64_t iter, index; + + bcache = arg; + if (!bcache) + return -pte_internal; + + memset(&exp, 0x00, sizeof(exp)); + exp.ninsn = 5; + exp.displacement = 28; + exp.mode = ptem_64bit; + exp.qualifier = ptbq_again; + exp.isize = 3; + + for (index = 0; index < bfix_nentries; ++index) { + for (iter = 0; iter < bfix_iterations; ++iter) { + struct pt_bcache_entry bce; + int errcode; + + memset(&bce, 0xff, sizeof(bce)); + + errcode = pt_bcache_lookup(&bce, bcache, index); + if (errcode < 0) + return errcode; + + if (!pt_bce_is_valid(bce)) { + errcode = pt_bcache_add(bcache, index, exp); + if (errcode < 0) + return errcode; + } + + errcode = pt_bcache_lookup(&bce, bcache, index); + if (errcode < 0) + return errcode; + + if (!pt_bce_is_valid(bce)) + return -pte_nosync; + + if (bce.ninsn != exp.ninsn) + return -pte_nosync; + + if (bce.displacement != exp.displacement) + return -pte_nosync; + + if (pt_bce_exec_mode(bce) != pt_bce_exec_mode(exp)) + return -pte_nosync; + + if (pt_bce_qualifier(bce) != pt_bce_qualifier(exp)) + return -pte_nosync; + + if (bce.isize != exp.isize) + return -pte_nosync; + } + } + + return 0; +} + +static struct ptunit_result stress(struct bcache_fixture *bfix) +{ + int errcode; + +#if defined(FEATURE_THREADS) + { + int thrd; + + for (thrd = 0; thrd < bfix_threads; ++thrd) + ptu_test(ptunit_thrd_create, &bfix->thrd, worker, + bfix->bcache); + } +#endif /* defined(FEATURE_THREADS) */ + + errcode = worker(bfix->bcache); + ptu_int_eq(errcode, 0); + + return ptu_passed(); +} + +int main(int argc, char **argv) +{ + struct bcache_fixture bfix, cfix; + struct ptunit_suite suite; + + bfix.init = bfix_init; + bfix.fini = bfix_fini; + + cfix.init = cfix_init; + cfix.fini = bfix_fini; + + suite = ptunit_mk_suite(argc, argv); + + ptu_run(suite, bcache_entry_size); + ptu_run(suite, bcache_size); + + ptu_run(suite, free_null); + ptu_run(suite, add_null); + ptu_run(suite, lookup_null); + + ptu_run_f(suite, alloc, cfix); + ptu_run_f(suite, alloc_min, cfix); + ptu_run_f(suite, alloc_too_big, cfix); + ptu_run_f(suite, alloc_zero, cfix); + + ptu_run_f(suite, initially_empty, bfix); + + ptu_run_f(suite, add_bad_index, bfix); + ptu_run_f(suite, lookup_bad_index, bfix); + + ptu_run_fp(suite, add, bfix, 0ull); + ptu_run_fp(suite, add, bfix, bfix_nentries - 1ull); + ptu_run_f(suite, stress, bfix); + + return ptunit_report(&suite); +} diff --git a/libipt/test/src/ptunit-block_decoder.c b/libipt/test/src/ptunit-block_decoder.c new file mode 100644 index 0000000000000..89de0cb289143 --- /dev/null +++ b/libipt/test/src/ptunit-block_decoder.c @@ -0,0 +1,351 @@ +/* + * Copyright (c) 2019, Intel Corporation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of Intel Corporation nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "ptunit.h" + +#include "pt_block_decoder.h" + +#include "intel-pt.h" + + +/* A test fixture providing a decoder operating on a small buffer. */ +struct test_fixture { + /* The packet_decoder. */ + struct pt_block_decoder decoder; + + /* The configuration. */ + struct pt_config config; + + /* The buffer it operates on. */ + uint8_t buffer[24]; + + /* The test fixture initialization and finalization functions. */ + struct ptunit_result (*init)(struct test_fixture *tfix); + struct ptunit_result (*fini)(struct test_fixture *tfix); +}; + +static struct ptunit_result tfix_init(struct test_fixture *tfix) +{ + struct pt_config *config; + uint8_t *buffer; + int errcode; + + config = &tfix->config; + buffer = tfix->buffer; + + memset(buffer, 0, sizeof(tfix->buffer)); + + pt_config_init(config); + config->begin = buffer; + config->end = buffer + sizeof(tfix->buffer); + + errcode = pt_blk_decoder_init(&tfix->decoder, config); + ptu_int_eq(errcode, 0); + + return ptu_passed(); +} + +static struct ptunit_result decoder_init_null(void) +{ + struct pt_block_decoder decoder; + struct pt_config config; + int errcode; + + errcode = pt_blk_decoder_init(NULL, &config); + ptu_int_eq(errcode, -pte_internal); + + errcode = pt_blk_decoder_init(&decoder, NULL); + ptu_int_eq(errcode, -pte_invalid); + + return ptu_passed(); +} + +static struct ptunit_result decoder_fini_null(void) +{ + pt_blk_decoder_fini(NULL); + + return ptu_passed(); +} + +static struct ptunit_result alloc_decoder_null(void) +{ + struct pt_block_decoder *decoder; + + decoder = pt_blk_alloc_decoder(NULL); + ptu_null(decoder); + + return ptu_passed(); +} + +static struct ptunit_result free_decoder_null(void) +{ + pt_blk_free_decoder(NULL); + + return ptu_passed(); +} + +static struct ptunit_result sync_forward_null(void) +{ + int errcode; + + errcode = pt_blk_sync_forward(NULL); + ptu_int_eq(errcode, -pte_invalid); + + return ptu_passed(); +} + +static struct ptunit_result sync_backward_null(void) +{ + int errcode; + + errcode = pt_blk_sync_backward(NULL); + ptu_int_eq(errcode, -pte_invalid); + + return ptu_passed(); +} + +static struct ptunit_result sync_set_null(void) +{ + int errcode; + + errcode = pt_blk_sync_set(NULL, 0ull); + ptu_int_eq(errcode, -pte_invalid); + + return ptu_passed(); +} + +static struct ptunit_result sync_set_eos(struct test_fixture *tfix) +{ + int errcode; + + errcode = pt_blk_sync_set(&tfix->decoder, sizeof(tfix->buffer) + 1); + ptu_int_eq(errcode, -pte_eos); + + return ptu_passed(); +} + +static struct ptunit_result get_offset_null(void) +{ + struct pt_block_decoder decoder; + uint64_t offset; + int errcode; + + errcode = pt_blk_get_offset(NULL, &offset); + ptu_int_eq(errcode, -pte_invalid); + + errcode = pt_blk_get_offset(&decoder, NULL); + ptu_int_eq(errcode, -pte_invalid); + + return ptu_passed(); +} + +static struct ptunit_result get_offset_init(struct test_fixture *tfix) +{ + uint64_t offset; + int errcode; + + errcode = pt_blk_get_offset(&tfix->decoder, &offset); + ptu_int_eq(errcode, -pte_nosync); + + return ptu_passed(); +} + +static struct ptunit_result get_sync_offset_null(void) +{ + struct pt_block_decoder decoder; + uint64_t offset; + int errcode; + + errcode = pt_blk_get_sync_offset(NULL, &offset); + ptu_int_eq(errcode, -pte_invalid); + + errcode = pt_blk_get_sync_offset(&decoder, NULL); + ptu_int_eq(errcode, -pte_invalid); + + return ptu_passed(); +} + +static struct ptunit_result get_image_null(void) +{ + const struct pt_image *image; + + image = pt_blk_get_image(NULL); + ptu_null(image); + + return ptu_passed(); +} + +static struct ptunit_result set_image_null(void) +{ + struct pt_image image; + int errcode; + + errcode = pt_blk_set_image(NULL, &image); + ptu_int_eq(errcode, -pte_invalid); + + errcode = pt_blk_set_image(NULL, NULL); + ptu_int_eq(errcode, -pte_invalid); + + return ptu_passed(); +} + +static struct ptunit_result get_config_null(void) +{ + const struct pt_config *config; + + config = pt_blk_get_config(NULL); + ptu_null(config); + + return ptu_passed(); +} + +static struct ptunit_result get_config(struct test_fixture *tfix) +{ + const struct pt_config *config; + + config = pt_blk_get_config(&tfix->decoder); + ptu_ptr(config); + + return ptu_passed(); +} + +static struct ptunit_result time_null(void) +{ + struct pt_block_decoder decoder; + uint64_t time; + uint32_t lost_mtc, lost_cyc; + int errcode; + + errcode = pt_blk_time(NULL, &time, &lost_mtc, &lost_cyc); + ptu_int_eq(errcode, -pte_invalid); + + errcode = pt_blk_time(&decoder, NULL, &lost_mtc, &lost_cyc); + ptu_int_eq(errcode, -pte_invalid); + + return ptu_passed(); +} + +static struct ptunit_result cbr_null(void) +{ + struct pt_block_decoder decoder; + uint32_t cbr; + int errcode; + + errcode = pt_blk_core_bus_ratio(NULL, &cbr); + ptu_int_eq(errcode, -pte_invalid); + + errcode = pt_blk_core_bus_ratio(&decoder, NULL); + ptu_int_eq(errcode, -pte_invalid); + + return ptu_passed(); +} + +static struct ptunit_result asid_null(void) +{ + struct pt_block_decoder decoder; + struct pt_asid asid; + int errcode; + + errcode = pt_blk_asid(NULL, &asid, sizeof(asid)); + ptu_int_eq(errcode, -pte_invalid); + + errcode = pt_blk_asid(&decoder, NULL, sizeof(asid)); + ptu_int_eq(errcode, -pte_invalid); + + return ptu_passed(); +} + +static struct ptunit_result next_null(void) +{ + struct pt_block_decoder decoder; + struct pt_block block; + int errcode; + + errcode = pt_blk_next(NULL, &block, sizeof(block)); + ptu_int_eq(errcode, -pte_invalid); + + errcode = pt_blk_next(&decoder, NULL, sizeof(block)); + ptu_int_eq(errcode, -pte_invalid); + + return ptu_passed(); +} + +static struct ptunit_result event_null(void) +{ + struct pt_block_decoder decoder; + struct pt_event event; + int errcode; + + errcode = pt_blk_event(NULL, &event, sizeof(event)); + ptu_int_eq(errcode, -pte_invalid); + + errcode = pt_blk_event(&decoder, NULL, sizeof(event)); + ptu_int_eq(errcode, -pte_invalid); + + return ptu_passed(); +} + +int main(int argc, char **argv) +{ + struct test_fixture tfix; + struct ptunit_suite suite; + + tfix.init = tfix_init; + tfix.fini = NULL; + + suite = ptunit_mk_suite(argc, argv); + + ptu_run(suite, decoder_init_null); + ptu_run(suite, decoder_fini_null); + ptu_run(suite, alloc_decoder_null); + ptu_run(suite, free_decoder_null); + + ptu_run(suite, sync_forward_null); + ptu_run(suite, sync_backward_null); + ptu_run(suite, sync_set_null); + ptu_run_f(suite, sync_set_eos, tfix); + + ptu_run(suite, get_offset_null); + ptu_run_f(suite, get_offset_init, tfix); + ptu_run(suite, get_sync_offset_null); + + ptu_run(suite, get_image_null); + ptu_run(suite, set_image_null); + + ptu_run(suite, get_config_null); + ptu_run_f(suite, get_config, tfix); + + ptu_run(suite, time_null); + ptu_run(suite, cbr_null); + ptu_run(suite, asid_null); + + ptu_run(suite, next_null); + ptu_run(suite, event_null); + + return ptunit_report(&suite); +} diff --git a/libipt/test/src/ptunit-config.c b/libipt/test/src/ptunit-config.c new file mode 100644 index 0000000000000..1cf7dbffb0cfd --- /dev/null +++ b/libipt/test/src/ptunit-config.c @@ -0,0 +1,562 @@ +/* + * Copyright (c) 2015-2019, Intel Corporation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of Intel Corporation nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "ptunit.h" + +#include "pt_config.h" +#include "pt_opcodes.h" + +#include "intel-pt.h" + +#include <stddef.h> + + +/* A global fake buffer to pacify static analyzers. */ +static uint8_t buffer[8]; + +static struct ptunit_result from_user_null(void) +{ + struct pt_config config; + int errcode; + + errcode = pt_config_from_user(NULL, &config); + ptu_int_eq(errcode, -pte_internal); + + errcode = pt_config_from_user(&config, NULL); + ptu_int_eq(errcode, -pte_invalid); + + return ptu_passed(); +} + +static struct ptunit_result from_user_too_small(void) +{ + struct pt_config config, user; + int errcode; + + user.size = sizeof(config.size); + + errcode = pt_config_from_user(&config, &user); + ptu_int_eq(errcode, -pte_bad_config); + + return ptu_passed(); +} + +static struct ptunit_result from_user_bad_buffer(void) +{ + struct pt_config config, user; + int errcode; + + pt_config_init(&user); + + errcode = pt_config_from_user(&config, &user); + ptu_int_eq(errcode, -pte_bad_config); + + user.begin = buffer; + + errcode = pt_config_from_user(&config, &user); + ptu_int_eq(errcode, -pte_bad_config); + + user.begin = NULL; + user.end = buffer; + + errcode = pt_config_from_user(&config, &user); + ptu_int_eq(errcode, -pte_bad_config); + + user.begin = &buffer[1]; + user.end = buffer; + + errcode = pt_config_from_user(&config, &user); + ptu_int_eq(errcode, -pte_bad_config); + + return ptu_passed(); +} + +static struct ptunit_result from_user(void) +{ + struct pt_config config, user; + int errcode; + + user.size = sizeof(user); + user.begin = buffer; + user.end = &buffer[sizeof(buffer)]; + user.cpu.vendor = pcv_intel; + user.errata.bdm70 = 1; + + errcode = pt_config_from_user(&config, &user); + ptu_int_eq(errcode, 0); + ptu_uint_eq(config.size, sizeof(config)); + ptu_ptr_eq(config.begin, buffer); + ptu_ptr_eq(config.end, &buffer[sizeof(buffer)]); + ptu_int_eq(config.cpu.vendor, pcv_intel); + ptu_uint_eq(config.errata.bdm70, 1); + + return ptu_passed(); +} + +static struct ptunit_result from_user_small(void) +{ + struct pt_config config, user; + int errcode; + + memset(&config, 0xcd, sizeof(config)); + + user.size = offsetof(struct pt_config, cpu); + user.begin = buffer; + user.end = &buffer[sizeof(buffer)]; + + errcode = pt_config_from_user(&config, &user); + ptu_int_eq(errcode, 0); + ptu_uint_eq(config.size, offsetof(struct pt_config, cpu)); + ptu_ptr_eq(config.begin, buffer); + ptu_ptr_eq(config.end, &buffer[sizeof(buffer)]); + ptu_int_eq(config.cpu.vendor, pcv_unknown); + ptu_uint_eq(config.errata.bdm70, 0); + + return ptu_passed(); +} + +static struct ptunit_result from_user_big(void) +{ + struct pt_config config, user; + int errcode; + + user.size = sizeof(user) + 4; + user.begin = buffer; + user.end = &buffer[sizeof(buffer)]; + user.cpu.vendor = pcv_intel; + user.errata.bdm70 = 1; + + errcode = pt_config_from_user(&config, &user); + ptu_int_eq(errcode, 0); + ptu_uint_eq(config.size, sizeof(config)); + ptu_ptr_eq(config.begin, buffer); + ptu_ptr_eq(config.end, &buffer[sizeof(buffer)]); + ptu_int_eq(config.cpu.vendor, pcv_intel); + ptu_uint_eq(config.errata.bdm70, 1); + + return ptu_passed(); +} + +static struct ptunit_result size(void) +{ + ptu_uint_eq(sizeof(struct pt_errata), 16 * 4); + + return ptu_passed(); +} + +static struct ptunit_result addr_filter_size(void) +{ + struct pt_conf_addr_filter conf; + + ptu_uint_eq(sizeof(conf.config), 8); + + return ptu_passed(); +} + +static struct ptunit_result addr_filter_none(void) +{ + struct pt_config config; + uint8_t filter; + + pt_config_init(&config); + + ptu_uint_eq(config.addr_filter.config.addr_cfg, 0ull); + + for (filter = 0; filter < 4; ++filter) { + uint32_t addr_cfg; + + addr_cfg = pt_filter_addr_cfg(&config.addr_filter, filter); + + ptu_uint_eq(addr_cfg, pt_addr_cfg_disabled); + } + + return ptu_passed(); +} + +static struct ptunit_result addr_filter_0(void) +{ + struct pt_config config; + uint64_t addr_a, addr_b; + uint32_t addr_cfg; + uint8_t filter; + + pt_config_init(&config); + config.addr_filter.config.ctl.addr0_cfg = pt_addr_cfg_filter; + config.addr_filter.addr0_a = 0xa000ull; + config.addr_filter.addr0_b = 0xb000ull; + + ptu_uint_ne(config.addr_filter.config.addr_cfg, 0ull); + + addr_cfg = pt_filter_addr_cfg(&config.addr_filter, 0); + ptu_uint_eq(addr_cfg, pt_addr_cfg_filter); + + addr_a = pt_filter_addr_a(&config.addr_filter, 0); + ptu_uint_eq(addr_a, 0xa000ull); + + addr_b = pt_filter_addr_b(&config.addr_filter, 0); + ptu_uint_eq(addr_b, 0xb000ull); + + for (filter = 1; filter < 4; ++filter) { + + addr_cfg = pt_filter_addr_cfg(&config.addr_filter, filter); + + ptu_uint_eq(addr_cfg, pt_addr_cfg_disabled); + } + + return ptu_passed(); +} + +static struct ptunit_result addr_filter_1_3(void) +{ + struct pt_config config; + uint64_t addr_a, addr_b; + uint32_t addr_cfg; + + pt_config_init(&config); + config.addr_filter.config.ctl.addr1_cfg = pt_addr_cfg_filter; + config.addr_filter.addr1_a = 0xa000ull; + config.addr_filter.addr1_b = 0xb000ull; + config.addr_filter.config.ctl.addr3_cfg = pt_addr_cfg_stop; + config.addr_filter.addr3_a = 0x100a000ull; + config.addr_filter.addr3_b = 0x100b000ull; + + ptu_uint_ne(config.addr_filter.config.addr_cfg, 0ull); + + addr_cfg = pt_filter_addr_cfg(&config.addr_filter, 0); + ptu_uint_eq(addr_cfg, pt_addr_cfg_disabled); + + addr_cfg = pt_filter_addr_cfg(&config.addr_filter, 1); + ptu_uint_eq(addr_cfg, pt_addr_cfg_filter); + + addr_a = pt_filter_addr_a(&config.addr_filter, 1); + ptu_uint_eq(addr_a, 0xa000ull); + + addr_b = pt_filter_addr_b(&config.addr_filter, 1); + ptu_uint_eq(addr_b, 0xb000ull); + + addr_cfg = pt_filter_addr_cfg(&config.addr_filter, 2); + ptu_uint_eq(addr_cfg, pt_addr_cfg_disabled); + + addr_cfg = pt_filter_addr_cfg(&config.addr_filter, 3); + ptu_uint_eq(addr_cfg, pt_addr_cfg_stop); + + addr_a = pt_filter_addr_a(&config.addr_filter, 3); + ptu_uint_eq(addr_a, 0x100a000ull); + + addr_b = pt_filter_addr_b(&config.addr_filter, 3); + ptu_uint_eq(addr_b, 0x100b000ull); + + return ptu_passed(); +} + +static struct ptunit_result addr_filter_oob(uint8_t filter) +{ + struct pt_config config; + uint64_t addr_a, addr_b; + uint32_t addr_cfg; + + pt_config_init(&config); + + memset(&config.addr_filter, 0xcc, sizeof(config.addr_filter)); + + addr_cfg = pt_filter_addr_cfg(&config.addr_filter, filter); + ptu_uint_eq(addr_cfg, pt_addr_cfg_disabled); + + addr_a = pt_filter_addr_a(&config.addr_filter, filter); + ptu_uint_eq(addr_a, 0ull); + + addr_b = pt_filter_addr_b(&config.addr_filter, filter); + ptu_uint_eq(addr_b, 0ull); + + return ptu_passed(); +} + +static struct ptunit_result addr_filter_ip_in(void) +{ + struct pt_config config; + int status; + + pt_config_init(&config); + config.addr_filter.config.ctl.addr1_cfg = pt_addr_cfg_filter; + config.addr_filter.addr1_a = 0xa000; + config.addr_filter.addr1_b = 0xb000; + config.addr_filter.config.ctl.addr3_cfg = pt_addr_cfg_filter; + config.addr_filter.addr3_a = 0x10a000; + config.addr_filter.addr3_b = 0x10b000; + + status = pt_filter_addr_check(&config.addr_filter, 0xa000); + ptu_int_eq(status, 1); + + status = pt_filter_addr_check(&config.addr_filter, 0xaf00); + ptu_int_eq(status, 1); + + status = pt_filter_addr_check(&config.addr_filter, 0xb000); + ptu_int_eq(status, 1); + + status = pt_filter_addr_check(&config.addr_filter, 0x10a000); + ptu_int_eq(status, 1); + + status = pt_filter_addr_check(&config.addr_filter, 0x10af00); + ptu_int_eq(status, 1); + + status = pt_filter_addr_check(&config.addr_filter, 0x10b000); + ptu_int_eq(status, 1); + + return ptu_passed(); +} + +static struct ptunit_result addr_filter_ip_out(void) +{ + struct pt_config config; + int status; + + pt_config_init(&config); + config.addr_filter.config.ctl.addr1_cfg = pt_addr_cfg_filter; + config.addr_filter.addr1_a = 0xa000; + config.addr_filter.addr1_b = 0xb000; + config.addr_filter.config.ctl.addr3_cfg = pt_addr_cfg_filter; + config.addr_filter.addr3_a = 0x10a000; + config.addr_filter.addr3_b = 0x10b000; + + status = pt_filter_addr_check(&config.addr_filter, 0xfff); + ptu_int_eq(status, 0); + + status = pt_filter_addr_check(&config.addr_filter, 0xb001); + ptu_int_eq(status, 0); + + status = pt_filter_addr_check(&config.addr_filter, 0x100fff); + ptu_int_eq(status, 0); + + status = pt_filter_addr_check(&config.addr_filter, 0x10b001); + ptu_int_eq(status, 0); + + return ptu_passed(); +} + +static struct ptunit_result addr_filter_stop_in(void) +{ + struct pt_config config; + int status; + + pt_config_init(&config); + config.addr_filter.config.ctl.addr1_cfg = pt_addr_cfg_stop; + config.addr_filter.addr1_a = 0xa000; + config.addr_filter.addr1_b = 0xb000; + config.addr_filter.config.ctl.addr3_cfg = pt_addr_cfg_stop; + config.addr_filter.addr3_a = 0x10a000; + config.addr_filter.addr3_b = 0x10b000; + + status = pt_filter_addr_check(&config.addr_filter, 0xa000); + ptu_int_eq(status, 0); + + status = pt_filter_addr_check(&config.addr_filter, 0xaf00); + ptu_int_eq(status, 0); + + status = pt_filter_addr_check(&config.addr_filter, 0xb000); + ptu_int_eq(status, 0); + + status = pt_filter_addr_check(&config.addr_filter, 0x10a000); + ptu_int_eq(status, 0); + + status = pt_filter_addr_check(&config.addr_filter, 0x10af00); + ptu_int_eq(status, 0); + + status = pt_filter_addr_check(&config.addr_filter, 0x10b000); + ptu_int_eq(status, 0); + + return ptu_passed(); +} + +static struct ptunit_result addr_filter_stop_out(void) +{ + struct pt_config config; + int status; + + pt_config_init(&config); + config.addr_filter.config.ctl.addr1_cfg = pt_addr_cfg_stop; + config.addr_filter.addr1_a = 0xa000; + config.addr_filter.addr1_b = 0xb000; + config.addr_filter.config.ctl.addr3_cfg = pt_addr_cfg_stop; + config.addr_filter.addr3_a = 0x10a000; + config.addr_filter.addr3_b = 0x10b000; + + status = pt_filter_addr_check(&config.addr_filter, 0xfff); + ptu_int_eq(status, 1); + + status = pt_filter_addr_check(&config.addr_filter, 0xb001); + ptu_int_eq(status, 1); + + status = pt_filter_addr_check(&config.addr_filter, 0x100fff); + ptu_int_eq(status, 1); + + status = pt_filter_addr_check(&config.addr_filter, 0x10b001); + ptu_int_eq(status, 1); + + return ptu_passed(); +} + +static struct ptunit_result addr_filter_ip_out_stop_in(void) +{ + struct pt_config config; + int status; + + pt_config_init(&config); + config.addr_filter.config.ctl.addr1_cfg = pt_addr_cfg_filter; + config.addr_filter.addr1_a = 0x100f00; + config.addr_filter.addr1_b = 0x10af00; + config.addr_filter.config.ctl.addr3_cfg = pt_addr_cfg_stop; + config.addr_filter.addr3_a = 0x10a000; + config.addr_filter.addr3_b = 0x10b000; + + status = pt_filter_addr_check(&config.addr_filter, 0x10af01); + ptu_int_eq(status, 0); + + status = pt_filter_addr_check(&config.addr_filter, 0x10b000); + ptu_int_eq(status, 0); + + return ptu_passed(); +} + +static struct ptunit_result addr_filter_ip_in_stop_in(void) +{ + struct pt_config config; + int status; + + pt_config_init(&config); + config.addr_filter.config.ctl.addr1_cfg = pt_addr_cfg_filter; + config.addr_filter.addr1_a = 0x100f00; + config.addr_filter.addr1_b = 0x10af00; + config.addr_filter.config.ctl.addr3_cfg = pt_addr_cfg_stop; + config.addr_filter.addr3_a = 0x10a000; + config.addr_filter.addr3_b = 0x10b000; + + status = pt_filter_addr_check(&config.addr_filter, 0x10af00); + ptu_int_eq(status, 0); + + status = pt_filter_addr_check(&config.addr_filter, 0x10a0ff); + ptu_int_eq(status, 0); + + return ptu_passed(); +} + +static struct ptunit_result cpu_errata_null(void) +{ + struct pt_errata errata; + struct pt_cpu cpu; + int errcode; + + errcode = pt_cpu_errata(&errata, NULL); + ptu_int_eq(errcode, -pte_invalid); + + errcode = pt_cpu_errata(NULL, &cpu); + ptu_int_eq(errcode, -pte_invalid); + + return ptu_passed(); +} + +static struct ptunit_result cpu_errata_unknown(void) +{ + struct pt_errata errata; + struct pt_cpu cpu; + int errcode; + + memset(&cpu, 0, sizeof(cpu)); + + errcode = pt_cpu_errata(&errata, &cpu); + ptu_int_eq(errcode, -pte_bad_cpu); + + return ptu_passed(); +} + +static struct ptunit_result cpu_errata_bad_vendor(void) +{ + struct pt_errata errata; + struct pt_cpu cpu; + int errcode; + + memset(&cpu, 0, sizeof(cpu)); + cpu.vendor = (enum pt_cpu_vendor) 0xffff; + + errcode = pt_cpu_errata(&errata, &cpu); + ptu_int_eq(errcode, -pte_bad_cpu); + + return ptu_passed(); +} + +static struct ptunit_result cpu_errata_bad_cpuid(void) +{ + struct pt_errata errata; + struct pt_cpu cpu; + int errcode; + + memset(&cpu, 0, sizeof(cpu)); + cpu.vendor = pcv_intel; + cpu.family = 6; + cpu.model = 63; + + errcode = pt_cpu_errata(&errata, &cpu); + ptu_int_eq(errcode, -pte_bad_cpu); + + return ptu_passed(); +} + +int main(int argc, char **argv) +{ + struct ptunit_suite suite; + + suite = ptunit_mk_suite(argc, argv); + + ptu_run(suite, from_user_null); + ptu_run(suite, from_user_too_small); + ptu_run(suite, from_user_bad_buffer); + ptu_run(suite, from_user); + ptu_run(suite, from_user_small); + ptu_run(suite, from_user_big); + ptu_run(suite, size); + + ptu_run(suite, addr_filter_size); + ptu_run(suite, addr_filter_none); + ptu_run(suite, addr_filter_0); + ptu_run(suite, addr_filter_1_3); + ptu_run_p(suite, addr_filter_oob, 255); + ptu_run_p(suite, addr_filter_oob, 8); + + ptu_run(suite, addr_filter_ip_in); + ptu_run(suite, addr_filter_ip_out); + ptu_run(suite, addr_filter_stop_in); + ptu_run(suite, addr_filter_stop_out); + ptu_run(suite, addr_filter_ip_out_stop_in); + ptu_run(suite, addr_filter_ip_in_stop_in); + + ptu_run(suite, cpu_errata_null); + ptu_run(suite, cpu_errata_unknown); + ptu_run(suite, cpu_errata_bad_vendor); + ptu_run(suite, cpu_errata_bad_cpuid); + + return ptunit_report(&suite); +} diff --git a/libipt/test/src/ptunit-cpp.cpp b/libipt/test/src/ptunit-cpp.cpp new file mode 100644 index 0000000000000..f288cbc531415 --- /dev/null +++ b/libipt/test/src/ptunit-cpp.cpp @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2013-2019, Intel Corporation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of Intel Corporation nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "ptunit.h" + +#include "intel-pt.h" + + +static struct ptunit_result init_packet_decoder(void) +{ + uint8_t buf[1]; + struct pt_config config; + struct pt_packet_decoder *decoder; + + pt_config_init(&config); + config.begin = buf; + config.end = buf + sizeof(buf); + + decoder = pt_pkt_alloc_decoder(&config); + ptu_ptr(decoder); + pt_pkt_free_decoder(decoder); + + return ptu_passed(); +} + +static struct ptunit_result init_query_decoder(void) +{ + uint8_t buf[1]; + struct pt_config config; + struct pt_query_decoder *query_decoder; + + pt_config_init(&config); + config.begin = buf; + config.end = buf + sizeof(buf); + + query_decoder = pt_qry_alloc_decoder(&config); + ptu_ptr(query_decoder); + pt_qry_free_decoder(query_decoder); + + return ptu_passed(); +} + +int main(int argc, char **argv) +{ + struct ptunit_suite suite; + + suite = ptunit_mk_suite(argc, argv); + + ptu_run(suite, init_packet_decoder); + ptu_run(suite, init_query_decoder); + + return ptunit_report(&suite); +} diff --git a/libipt/test/src/ptunit-cpu.c b/libipt/test/src/ptunit-cpu.c new file mode 100644 index 0000000000000..bd49368a6fc2a --- /dev/null +++ b/libipt/test/src/ptunit-cpu.c @@ -0,0 +1,173 @@ +/* + * Copyright (c) 2013-2019, Intel Corporation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of Intel Corporation nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "ptunit.h" + +#include "pt_cpu.h" +#include "pt_cpuid.h" + +#include "intel-pt.h" + +#include <stdlib.h> + + +void pt_cpuid(uint32_t leaf, uint32_t *eax, uint32_t *ebx, uint32_t *ecx, + uint32_t *edx) +{ + (void) leaf; + (void) eax; + (void) ebx; + (void) ecx; + (void) edx; +} + + +static struct ptunit_result cpu_valid(void) +{ + struct pt_cpu cpu; + int error; + + error = pt_cpu_parse(&cpu, "6/44/2"); + ptu_int_eq(error, 0); + ptu_int_eq(cpu.vendor, pcv_intel); + ptu_uint_eq(cpu.family, 6); + ptu_uint_eq(cpu.model, 44); + ptu_uint_eq(cpu.stepping, 2); + + error = pt_cpu_parse(&cpu, "0xf/0x2c/0xf"); + ptu_int_eq(error, 0); + ptu_int_eq(cpu.vendor, pcv_intel); + ptu_uint_eq(cpu.family, 0xf); + ptu_uint_eq(cpu.model, 0x2c); + ptu_uint_eq(cpu.stepping, 0xf); + + error = pt_cpu_parse(&cpu, "022/054/017"); + ptu_int_eq(error, 0); + ptu_int_eq(cpu.vendor, pcv_intel); + ptu_uint_eq(cpu.family, 022); + ptu_uint_eq(cpu.model, 054); + ptu_uint_eq(cpu.stepping, 017); + + error = pt_cpu_parse(&cpu, "6/44"); + ptu_int_eq(error, 0); + ptu_int_eq(cpu.vendor, pcv_intel); + ptu_uint_eq(cpu.family, 6); + ptu_uint_eq(cpu.model, 44); + ptu_uint_eq(cpu.stepping, 0); + + return ptu_passed(); +} + +static struct ptunit_result cpu_null(void) +{ + struct pt_cpu cpu; + int error; + + error = pt_cpu_parse(&cpu, NULL); + ptu_int_eq(error, -pte_invalid); + + error = pt_cpu_parse(NULL, ""); + ptu_int_eq(error, -pte_invalid); + + error = pt_cpu_parse(NULL, NULL); + ptu_int_eq(error, -pte_invalid); + + return ptu_passed(); +} + +static struct ptunit_result cpu_incomplete(void) +{ + struct pt_cpu cpu; + int error; + + error = pt_cpu_parse(&cpu, ""); + ptu_int_eq(error, -pte_invalid); + + error = pt_cpu_parse(&cpu, "6"); + ptu_int_eq(error, -pte_invalid); + + error = pt_cpu_parse(&cpu, "6/"); + ptu_int_eq(error, -pte_invalid); + + error = pt_cpu_parse(&cpu, "6//2"); + ptu_int_eq(error, -pte_invalid); + + error = pt_cpu_parse(&cpu, "//"); + ptu_int_eq(error, -pte_invalid); + + return ptu_passed(); +} + +static struct ptunit_result cpu_invalid(void) +{ + struct pt_cpu cpu; + int error; + + error = pt_cpu_parse(&cpu, "e/44/2"); + ptu_int_eq(error, -pte_invalid); + + error = pt_cpu_parse(&cpu, "6/e/2"); + ptu_int_eq(error, -pte_invalid); + + error = pt_cpu_parse(&cpu, "6/44/e"); + ptu_int_eq(error, -pte_invalid); + + error = pt_cpu_parse(&cpu, "65536/44/2"); + ptu_int_eq(error, -pte_invalid); + + error = pt_cpu_parse(&cpu, "6/256/2"); + ptu_int_eq(error, -pte_invalid); + + error = pt_cpu_parse(&cpu, "6/44/256"); + ptu_int_eq(error, -pte_invalid); + + error = pt_cpu_parse(&cpu, "-1/44/2"); + ptu_int_eq(error, -pte_invalid); + + error = pt_cpu_parse(&cpu, "6/-1/2"); + ptu_int_eq(error, -pte_invalid); + + error = pt_cpu_parse(&cpu, "6/44/-1"); + ptu_int_eq(error, -pte_invalid); + + return ptu_passed(); +} + +int main(int argc, char **argv) +{ + struct ptunit_suite suite; + + suite = ptunit_mk_suite(argc, argv); + + ptu_run(suite, cpu_valid); + ptu_run(suite, cpu_null); + ptu_run(suite, cpu_incomplete); + ptu_run(suite, cpu_invalid); + + return ptunit_report(&suite); +} diff --git a/libipt/test/src/ptunit-encoder.c b/libipt/test/src/ptunit-encoder.c new file mode 100644 index 0000000000000..215da2b7e83eb --- /dev/null +++ b/libipt/test/src/ptunit-encoder.c @@ -0,0 +1,237 @@ +/* + * Copyright (c) 2019, Intel Corporation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of Intel Corporation nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "ptunit.h" + +#include "pt_encoder.h" + +#include "intel-pt.h" + + +/* A test fixture providing a decoder operating on a small buffer. */ +struct test_fixture { + /* The encoder. */ + struct pt_encoder encoder; + + /* The configuration. */ + struct pt_config config; + + /* The buffer it operates on. */ + uint8_t buffer[24]; + + /* The test fixture initialization and finalization functions. */ + struct ptunit_result (*init)(struct test_fixture *tfix); + struct ptunit_result (*fini)(struct test_fixture *tfix); +}; + +static struct ptunit_result tfix_init(struct test_fixture *tfix) +{ + struct pt_config *config; + uint8_t *buffer; + int errcode; + + config = &tfix->config; + buffer = tfix->buffer; + + memset(buffer, 0, sizeof(tfix->buffer)); + + pt_config_init(config); + config->begin = buffer; + config->end = buffer + sizeof(tfix->buffer); + + errcode = pt_encoder_init(&tfix->encoder, config); + ptu_int_eq(errcode, 0); + + return ptu_passed(); +} + +static struct ptunit_result encoder_init_null(void) +{ + struct pt_encoder encoder; + struct pt_config config; + int errcode; + + errcode = pt_encoder_init(NULL, &config); + ptu_int_eq(errcode, -pte_invalid); + + errcode = pt_encoder_init(&encoder, NULL); + ptu_int_eq(errcode, -pte_invalid); + + return ptu_passed(); +} + +static struct ptunit_result encoder_fini_null(void) +{ + pt_encoder_fini(NULL); + + return ptu_passed(); +} + +static struct ptunit_result alloc_encoder_null(void) +{ + struct pt_encoder *encoder; + + encoder = pt_alloc_encoder(NULL); + ptu_null(encoder); + + return ptu_passed(); +} + +static struct ptunit_result free_encoder_null(void) +{ + pt_free_encoder(NULL); + + return ptu_passed(); +} + +static struct ptunit_result sync_set_null(void) +{ + int errcode; + + errcode = pt_enc_sync_set(NULL, 0ull); + ptu_int_eq(errcode, -pte_invalid); + + return ptu_passed(); +} + +static struct ptunit_result sync_set_eos(struct test_fixture *tfix) +{ + int errcode; + + errcode = pt_enc_sync_set(&tfix->encoder, sizeof(tfix->buffer) + 1); + ptu_int_eq(errcode, -pte_eos); + + return ptu_passed(); +} + +static struct ptunit_result get_offset_null(void) +{ + struct pt_encoder encoder; + uint64_t offset; + int errcode; + + errcode = pt_enc_get_offset(NULL, &offset); + ptu_int_eq(errcode, -pte_invalid); + + errcode = pt_enc_get_offset(&encoder, NULL); + ptu_int_eq(errcode, -pte_invalid); + + return ptu_passed(); +} + +static struct ptunit_result get_offset_init(struct test_fixture *tfix) +{ + uint64_t offset; + int errcode; + + errcode = pt_enc_get_offset(&tfix->encoder, &offset); + ptu_int_eq(errcode, 0); + ptu_uint_eq(offset, 0ull); + + return ptu_passed(); +} + +static struct ptunit_result sync_set_get_offset(struct test_fixture *tfix) +{ + uint64_t offset; + int errcode; + + errcode = pt_enc_sync_set(&tfix->encoder, 1ull); + ptu_int_eq(errcode, 0); + + errcode = pt_enc_get_offset(&tfix->encoder, &offset); + ptu_int_eq(errcode, 0); + ptu_uint_eq(offset, 1ull); + + return ptu_passed(); +} + +static struct ptunit_result get_config_null(void) +{ + const struct pt_config *config; + + config = pt_enc_get_config(NULL); + ptu_null(config); + + return ptu_passed(); +} + +static struct ptunit_result get_config(struct test_fixture *tfix) +{ + const struct pt_config *config; + + config = pt_enc_get_config(&tfix->encoder); + ptu_ptr(config); + + return ptu_passed(); +} + +static struct ptunit_result next_null(void) +{ + struct pt_encoder encoder; + struct pt_packet packet; + int errcode; + + errcode = pt_enc_next(NULL, &packet); + ptu_int_eq(errcode, -pte_invalid); + + errcode = pt_enc_next(&encoder, NULL); + ptu_int_eq(errcode, -pte_invalid); + + return ptu_passed(); +} + +int main(int argc, char **argv) +{ + struct test_fixture tfix; + struct ptunit_suite suite; + + tfix.init = tfix_init; + tfix.fini = NULL; + + suite = ptunit_mk_suite(argc, argv); + + ptu_run(suite, encoder_init_null); + ptu_run(suite, encoder_fini_null); + ptu_run(suite, alloc_encoder_null); + ptu_run(suite, free_encoder_null); + + ptu_run(suite, sync_set_null); + ptu_run_f(suite, sync_set_eos, tfix); + + ptu_run(suite, get_offset_null); + ptu_run_f(suite, get_offset_init, tfix); + ptu_run_f(suite, sync_set_get_offset, tfix); + + ptu_run(suite, get_config_null); + ptu_run_f(suite, get_config, tfix); + + ptu_run(suite, next_null); + + return ptunit_report(&suite); +} diff --git a/libipt/test/src/ptunit-event_queue.c b/libipt/test/src/ptunit-event_queue.c new file mode 100644 index 0000000000000..2a962e234e90d --- /dev/null +++ b/libipt/test/src/ptunit-event_queue.c @@ -0,0 +1,470 @@ +/* + * Copyright (c) 2014-2019, Intel Corporation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of Intel Corporation nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "ptunit.h" + +#include "pt_event_queue.h" + + +/* A test fixture providing an initialized event queue. */ +struct evq_fixture { + /* The event queue. */ + struct pt_event_queue evq; + + /* The test fixture initialization and finalization functions. */ + struct ptunit_result (*init)(struct evq_fixture *); + struct ptunit_result (*fini)(struct evq_fixture *); +}; + + +static struct ptunit_result efix_init(struct evq_fixture *efix) +{ + pt_evq_init(&efix->evq); + + return ptu_passed(); +} + +static struct ptunit_result efix_init_pending(struct evq_fixture *efix) +{ + struct pt_event *ev; + int evb; + + pt_evq_init(&efix->evq); + + for (evb = 0; evb < evb_max; ++evb) { + ev = pt_evq_enqueue(&efix->evq, (enum pt_event_binding) evb); + ptu_ptr(ev); + } + + return ptu_passed(); +} + +static struct ptunit_result standalone_null(void) +{ + struct pt_event *ev; + + ev = pt_evq_standalone(NULL); + ptu_null(ev); + + return ptu_passed(); +} + +static struct ptunit_result standalone(struct evq_fixture *efix) +{ + struct pt_event *ev; + + ev = pt_evq_standalone(&efix->evq); + ptu_ptr(ev); + ptu_uint_eq(ev->ip_suppressed, 0ul); + ptu_uint_eq(ev->status_update, 0ul); + + return ptu_passed(); +} + +static struct ptunit_result enqueue_null(enum pt_event_binding evb) +{ + struct pt_event *ev; + + ev = pt_evq_enqueue(NULL, evb); + ptu_null(ev); + + return ptu_passed(); +} + +static struct ptunit_result dequeue_null(enum pt_event_binding evb) +{ + struct pt_event *ev; + + ev = pt_evq_dequeue(NULL, evb); + ptu_null(ev); + + return ptu_passed(); +} + +static struct ptunit_result dequeue_empty(struct evq_fixture *efix, + enum pt_event_binding evb) +{ + struct pt_event *ev; + + ev = pt_evq_dequeue(&efix->evq, evb); + ptu_null(ev); + + return ptu_passed(); +} + +static struct ptunit_result evq_empty(struct evq_fixture *efix, + enum pt_event_binding evb) +{ + int status; + + status = pt_evq_empty(&efix->evq, evb); + ptu_int_gt(status, 0); + + status = pt_evq_pending(&efix->evq, evb); + ptu_int_eq(status, 0); + + return ptu_passed(); +} + +static struct ptunit_result evq_pending(struct evq_fixture *efix, + enum pt_event_binding evb) +{ + int status; + + status = pt_evq_empty(&efix->evq, evb); + ptu_int_eq(status, 0); + + status = pt_evq_pending(&efix->evq, evb); + ptu_int_gt(status, 0); + + return ptu_passed(); +} + +static struct ptunit_result evq_others_empty(struct evq_fixture *efix, + enum pt_event_binding evb) +{ + int other; + + for (other = 0; other < evb_max; ++other) { + enum pt_event_binding ob; + + ob = (enum pt_event_binding) other; + if (ob != evb) + ptu_test(evq_empty, efix, ob); + } + + return ptu_passed(); +} + +static struct ptunit_result enqueue_all_dequeue(struct evq_fixture *efix, + enum pt_event_binding evb, + size_t num) +{ + struct pt_event *in[evq_max], *out[evq_max]; + size_t idx; + + ptu_uint_le(num, evq_max - 2); + + for (idx = 0; idx < num; ++idx) { + in[idx] = pt_evq_enqueue(&efix->evq, evb); + ptu_ptr(in[idx]); + } + + ptu_test(evq_pending, efix, evb); + ptu_test(evq_others_empty, efix, evb); + + for (idx = 0; idx < num; ++idx) { + out[idx] = pt_evq_dequeue(&efix->evq, evb); + ptu_ptr_eq(out[idx], in[idx]); + } + + ptu_test(evq_empty, efix, evb); + + return ptu_passed(); +} + +static struct ptunit_result enqueue_one_dequeue(struct evq_fixture *efix, + enum pt_event_binding evb, + size_t num) +{ + size_t idx; + + for (idx = 0; idx < num; ++idx) { + struct pt_event *in, *out; + + in = pt_evq_enqueue(&efix->evq, evb); + ptu_ptr(in); + + out = pt_evq_dequeue(&efix->evq, evb); + ptu_ptr_eq(out, in); + } + + return ptu_passed(); +} + +static struct ptunit_result overflow(struct evq_fixture *efix, + enum pt_event_binding evb, + size_t num) +{ + struct pt_event *in[evq_max], *out[evq_max], *ev; + size_t idx; + + ptu_uint_le(num, evq_max - 2); + + for (idx = 0; idx < (evq_max - 2); ++idx) { + in[idx] = pt_evq_enqueue(&efix->evq, evb); + ptu_ptr(in[idx]); + } + + for (idx = 0; idx < num; ++idx) { + ev = pt_evq_enqueue(&efix->evq, evb); + ptu_null(ev); + } + + for (idx = 0; idx < num; ++idx) { + out[idx] = pt_evq_dequeue(&efix->evq, evb); + ptu_ptr_eq(out[idx], in[idx]); + } + + return ptu_passed(); +} + +static struct ptunit_result clear_null(enum pt_event_binding evb) +{ + int errcode; + + errcode = pt_evq_clear(NULL, evb); + ptu_int_eq(errcode, -pte_internal); + + return ptu_passed(); +} + +static struct ptunit_result clear(struct evq_fixture *efix, + enum pt_event_binding evb) +{ + int errcode; + + errcode = pt_evq_clear(&efix->evq, evb); + ptu_int_eq(errcode, 0); + + ptu_test(evq_empty, efix, evb); + + return ptu_passed(); +} + +static struct ptunit_result empty_null(enum pt_event_binding evb) +{ + int errcode; + + errcode = pt_evq_empty(NULL, evb); + ptu_int_eq(errcode, -pte_internal); + + return ptu_passed(); +} + +static struct ptunit_result pending_null(enum pt_event_binding evb) +{ + int errcode; + + errcode = pt_evq_pending(NULL, evb); + ptu_int_eq(errcode, -pte_internal); + + return ptu_passed(); +} + +static struct ptunit_result find_null(enum pt_event_binding evb, + enum pt_event_type evt) +{ + struct pt_event *ev; + + ev = pt_evq_find(NULL, evb, evt); + ptu_null(ev); + + return ptu_passed(); +} + +static struct ptunit_result find_empty(struct evq_fixture *efix, + enum pt_event_binding evb, + enum pt_event_type evt) +{ + struct pt_event *ev; + + ev = pt_evq_find(&efix->evq, evb, evt); + ptu_null(ev); + + return ptu_passed(); +} + +static struct ptunit_result find_none_evb(struct evq_fixture *efix, + enum pt_event_binding evb, + enum pt_event_type evt) +{ + struct pt_event *ev; + size_t other; + + for (other = 0; other < evb_max; ++other) { + enum pt_event_binding ob; + + ob = (enum pt_event_binding) other; + if (ob != evb) { + ev = pt_evq_enqueue(&efix->evq, ob); + ptu_ptr(ev); + + ev->type = evt; + } + } + + ev = pt_evq_find(&efix->evq, evb, evt); + ptu_null(ev); + + return ptu_passed(); +} + +static struct ptunit_result evq_enqueue_other(struct evq_fixture *efix, + enum pt_event_binding evb, + enum pt_event_type evt, + size_t num) +{ + enum pt_event_type ot; + struct pt_event *ev; + size_t other; + + for (other = 0; other < num; ++other) { + ot = (enum pt_event_type) other; + if (ot != evt) { + ev = pt_evq_enqueue(&efix->evq, evb); + ptu_ptr(ev); + + ev->type = ot; + } + } + + return ptu_passed(); +} + +static struct ptunit_result find_none_evt(struct evq_fixture *efix, + enum pt_event_binding evb, + enum pt_event_type evt, + size_t num) +{ + struct pt_event *ev; + + ptu_test(evq_enqueue_other, efix, evb, evt, num); + + ev = pt_evq_find(&efix->evq, evb, evt); + ptu_null(ev); + + return ptu_passed(); +} + +static struct ptunit_result find(struct evq_fixture *efix, + enum pt_event_binding evb, + enum pt_event_type evt, + size_t before, size_t after) +{ + struct pt_event *in, *out; + + ptu_test(evq_enqueue_other, efix, evb, evt, before); + + in = pt_evq_enqueue(&efix->evq, evb); + ptu_ptr(in); + + in->type = evt; + + ptu_test(evq_enqueue_other, efix, evb, evt, after); + + out = pt_evq_find(&efix->evq, evb, evt); + ptu_ptr_eq(out, in); + + return ptu_passed(); +} + +int main(int argc, char **argv) +{ + struct evq_fixture efix, pfix; + struct ptunit_suite suite; + + efix.init = efix_init; + efix.fini = NULL; + + pfix.init = efix_init_pending; + pfix.fini = NULL; + + suite = ptunit_mk_suite(argc, argv); + + ptu_run(suite, standalone_null); + ptu_run_f(suite, standalone, efix); + + ptu_run_p(suite, enqueue_null, evb_psbend); + ptu_run_p(suite, enqueue_null, evb_tip); + ptu_run_p(suite, enqueue_null, evb_fup); + + ptu_run_p(suite, dequeue_null, evb_psbend); + ptu_run_p(suite, dequeue_null, evb_tip); + ptu_run_p(suite, dequeue_null, evb_fup); + + ptu_run_fp(suite, dequeue_empty, efix, evb_psbend); + ptu_run_fp(suite, dequeue_empty, efix, evb_tip); + ptu_run_fp(suite, dequeue_empty, efix, evb_fup); + + ptu_run_fp(suite, enqueue_all_dequeue, efix, evb_psbend, 1); + ptu_run_fp(suite, enqueue_all_dequeue, efix, evb_psbend, 2); + ptu_run_fp(suite, enqueue_all_dequeue, efix, evb_tip, 1); + ptu_run_fp(suite, enqueue_all_dequeue, efix, evb_tip, 3); + ptu_run_fp(suite, enqueue_all_dequeue, efix, evb_fup, 1); + ptu_run_fp(suite, enqueue_all_dequeue, efix, evb_fup, 4); + + ptu_run_fp(suite, enqueue_one_dequeue, efix, evb_psbend, evb_max * 2); + ptu_run_fp(suite, enqueue_one_dequeue, efix, evb_tip, evb_max * 2); + ptu_run_fp(suite, enqueue_one_dequeue, efix, evb_fup, evb_max * 2); + + ptu_run_fp(suite, overflow, efix, evb_psbend, 1); + ptu_run_fp(suite, overflow, efix, evb_tip, 2); + ptu_run_fp(suite, overflow, efix, evb_fup, 3); + + ptu_run_p(suite, clear_null, evb_psbend); + ptu_run_p(suite, clear_null, evb_tip); + ptu_run_p(suite, clear_null, evb_fup); + + ptu_run_fp(suite, clear, efix, evb_psbend); + ptu_run_fp(suite, clear, pfix, evb_psbend); + ptu_run_fp(suite, clear, efix, evb_tip); + ptu_run_fp(suite, clear, pfix, evb_tip); + ptu_run_fp(suite, clear, efix, evb_fup); + ptu_run_fp(suite, clear, pfix, evb_fup); + + ptu_run_p(suite, empty_null, evb_psbend); + ptu_run_p(suite, empty_null, evb_tip); + ptu_run_p(suite, empty_null, evb_fup); + + ptu_run_p(suite, pending_null, evb_psbend); + ptu_run_p(suite, pending_null, evb_tip); + ptu_run_p(suite, pending_null, evb_fup); + + ptu_run_p(suite, find_null, evb_psbend, ptev_enabled); + ptu_run_p(suite, find_null, evb_tip, ptev_disabled); + ptu_run_p(suite, find_null, evb_fup, ptev_paging); + + ptu_run_fp(suite, find_empty, efix, evb_psbend, ptev_enabled); + ptu_run_fp(suite, find_empty, efix, evb_tip, ptev_disabled); + ptu_run_fp(suite, find_empty, efix, evb_fup, ptev_paging); + + ptu_run_fp(suite, find_none_evb, efix, evb_psbend, ptev_enabled); + ptu_run_fp(suite, find_none_evb, efix, evb_tip, ptev_disabled); + ptu_run_fp(suite, find_none_evb, efix, evb_fup, ptev_paging); + + ptu_run_fp(suite, find_none_evt, efix, evb_psbend, ptev_enabled, 3); + ptu_run_fp(suite, find_none_evt, efix, evb_tip, ptev_disabled, 4); + ptu_run_fp(suite, find_none_evt, efix, evb_fup, ptev_paging, 2); + + ptu_run_fp(suite, find, efix, evb_psbend, ptev_enabled, 0, 3); + ptu_run_fp(suite, find, efix, evb_tip, ptev_disabled, 2, 0); + ptu_run_fp(suite, find, efix, evb_fup, ptev_paging, 1, 4); + + return ptunit_report(&suite); +} diff --git a/libipt/test/src/ptunit-fetch.c b/libipt/test/src/ptunit-fetch.c new file mode 100644 index 0000000000000..d5981d56487e4 --- /dev/null +++ b/libipt/test/src/ptunit-fetch.c @@ -0,0 +1,693 @@ +/* + * Copyright (c) 2014-2019, Intel Corporation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of Intel Corporation nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "ptunit.h" + +#include "pt_decoder_function.h" +#include "pt_packet_decoder.h" +#include "pt_query_decoder.h" +#include "pt_encoder.h" +#include "pt_opcodes.h" + +#include "intel-pt.h" + + +/* A test fixture for decoder function fetch tests. */ +struct fetch_fixture { + /* The trace buffer. */ + uint8_t buffer[1024]; + + /* A trace configuration. */ + struct pt_config config; + + /* A trace encoder. */ + struct pt_encoder encoder; + + /* The test fixture initialization and finalization functions. */ + struct ptunit_result (*init)(struct fetch_fixture *); + struct ptunit_result (*fini)(struct fetch_fixture *); +}; + +static struct ptunit_result ffix_init(struct fetch_fixture *ffix) +{ + memset(ffix->buffer, pt_opc_bad, sizeof(ffix->buffer)); + + memset(&ffix->config, 0, sizeof(ffix->config)); + ffix->config.size = sizeof(ffix->config); + ffix->config.begin = ffix->buffer; + ffix->config.end = ffix->buffer + sizeof(ffix->buffer); + + pt_encoder_init(&ffix->encoder, &ffix->config); + + return ptu_passed(); +} + +static struct ptunit_result ffix_fini(struct fetch_fixture *ffix) +{ + pt_encoder_fini(&ffix->encoder); + + return ptu_passed(); +} + + +static struct ptunit_result fetch_null(struct fetch_fixture *ffix) +{ + const struct pt_decoder_function *dfun; + int errcode; + + errcode = pt_df_fetch(NULL, ffix->config.begin, &ffix->config); + ptu_int_eq(errcode, -pte_internal); + + errcode = pt_df_fetch(&dfun, NULL, &ffix->config); + ptu_int_eq(errcode, -pte_nosync); + + errcode = pt_df_fetch(&dfun, ffix->config.begin, NULL); + ptu_int_eq(errcode, -pte_internal); + + return ptu_passed(); +} + +static struct ptunit_result fetch_empty(struct fetch_fixture *ffix) +{ + const struct pt_decoder_function *dfun; + int errcode; + + errcode = pt_df_fetch(&dfun, ffix->config.end, &ffix->config); + ptu_int_eq(errcode, -pte_eos); + + return ptu_passed(); +} + +static struct ptunit_result fetch_unknown(struct fetch_fixture *ffix) +{ + const struct pt_decoder_function *dfun; + int errcode; + + ffix->config.begin[0] = pt_opc_bad; + + errcode = pt_df_fetch(&dfun, ffix->config.begin, &ffix->config); + ptu_int_eq(errcode, 0); + ptu_ptr_eq(dfun, &pt_decode_unknown); + + return ptu_passed(); +} + +static struct ptunit_result fetch_unknown_ext(struct fetch_fixture *ffix) +{ + const struct pt_decoder_function *dfun; + int errcode; + + ffix->config.begin[0] = pt_opc_ext; + ffix->config.begin[1] = pt_ext_bad; + + errcode = pt_df_fetch(&dfun, ffix->config.begin, &ffix->config); + ptu_int_eq(errcode, 0); + ptu_ptr_eq(dfun, &pt_decode_unknown); + + return ptu_passed(); +} + +static struct ptunit_result fetch_unknown_ext2(struct fetch_fixture *ffix) +{ + const struct pt_decoder_function *dfun; + int errcode; + + ffix->config.begin[0] = pt_opc_ext; + ffix->config.begin[1] = pt_ext_ext2; + ffix->config.begin[2] = pt_ext2_bad; + + errcode = pt_df_fetch(&dfun, ffix->config.begin, &ffix->config); + ptu_int_eq(errcode, 0); + ptu_ptr_eq(dfun, &pt_decode_unknown); + + return ptu_passed(); +} + +static struct ptunit_result fetch_packet(struct fetch_fixture *ffix, + const struct pt_packet *packet, + const struct pt_decoder_function *df) +{ + const struct pt_decoder_function *dfun; + int errcode; + + errcode = pt_enc_next(&ffix->encoder, packet); + ptu_int_ge(errcode, 0); + + errcode = pt_df_fetch(&dfun, ffix->config.begin, &ffix->config); + ptu_int_eq(errcode, 0); + ptu_ptr_eq(dfun, df); + + return ptu_passed(); +} + +static struct ptunit_result fetch_type(struct fetch_fixture *ffix, + enum pt_packet_type type, + const struct pt_decoder_function *dfun) +{ + struct pt_packet packet; + + memset(&packet, 0, sizeof(packet)); + packet.type = type; + + ptu_test(fetch_packet, ffix, &packet, dfun); + + return ptu_passed(); +} + +static struct ptunit_result fetch_tnt_8(struct fetch_fixture *ffix) +{ + struct pt_packet packet; + + memset(&packet, 0, sizeof(packet)); + packet.type = ppt_tnt_8; + packet.payload.tnt.bit_size = 1; + + ptu_test(fetch_packet, ffix, &packet, &pt_decode_tnt_8); + + return ptu_passed(); +} + +static struct ptunit_result fetch_mode_exec(struct fetch_fixture *ffix) +{ + struct pt_packet packet; + + memset(&packet, 0, sizeof(packet)); + packet.type = ppt_mode; + packet.payload.mode.leaf = pt_mol_exec; + + ptu_test(fetch_packet, ffix, &packet, &pt_decode_mode); + + return ptu_passed(); +} + +static struct ptunit_result fetch_mode_tsx(struct fetch_fixture *ffix) +{ + struct pt_packet packet; + + memset(&packet, 0, sizeof(packet)); + packet.type = ppt_mode; + packet.payload.mode.leaf = pt_mol_tsx; + + ptu_test(fetch_packet, ffix, &packet, &pt_decode_mode); + + return ptu_passed(); +} + +static struct ptunit_result fetch_exstop_ip(struct fetch_fixture *ffix) +{ + struct pt_packet packet; + + memset(&packet, 0, sizeof(packet)); + packet.type = ppt_exstop; + packet.payload.exstop.ip = 1; + + ptu_test(fetch_packet, ffix, &packet, &pt_decode_exstop); + + return ptu_passed(); +} + +int main(int argc, char **argv) +{ + struct fetch_fixture ffix; + struct ptunit_suite suite; + + ffix.init = ffix_init; + ffix.fini = ffix_fini; + + suite = ptunit_mk_suite(argc, argv); + + ptu_run_f(suite, fetch_null, ffix); + ptu_run_f(suite, fetch_empty, ffix); + + ptu_run_f(suite, fetch_unknown, ffix); + ptu_run_f(suite, fetch_unknown_ext, ffix); + ptu_run_f(suite, fetch_unknown_ext2, ffix); + + ptu_run_fp(suite, fetch_type, ffix, ppt_pad, &pt_decode_pad); + ptu_run_fp(suite, fetch_type, ffix, ppt_psb, &pt_decode_psb); + ptu_run_fp(suite, fetch_type, ffix, ppt_tip, &pt_decode_tip); + ptu_run_fp(suite, fetch_type, ffix, ppt_tnt_64, &pt_decode_tnt_64); + ptu_run_fp(suite, fetch_type, ffix, ppt_tip_pge, &pt_decode_tip_pge); + ptu_run_fp(suite, fetch_type, ffix, ppt_tip_pgd, &pt_decode_tip_pgd); + ptu_run_fp(suite, fetch_type, ffix, ppt_fup, &pt_decode_fup); + ptu_run_fp(suite, fetch_type, ffix, ppt_pip, &pt_decode_pip); + ptu_run_fp(suite, fetch_type, ffix, ppt_ovf, &pt_decode_ovf); + ptu_run_fp(suite, fetch_type, ffix, ppt_psbend, &pt_decode_psbend); + ptu_run_fp(suite, fetch_type, ffix, ppt_tsc, &pt_decode_tsc); + ptu_run_fp(suite, fetch_type, ffix, ppt_cbr, &pt_decode_cbr); + ptu_run_fp(suite, fetch_type, ffix, ppt_tma, &pt_decode_tma); + ptu_run_fp(suite, fetch_type, ffix, ppt_mtc, &pt_decode_mtc); + ptu_run_fp(suite, fetch_type, ffix, ppt_cyc, &pt_decode_cyc); + ptu_run_fp(suite, fetch_type, ffix, ppt_stop, &pt_decode_stop); + ptu_run_fp(suite, fetch_type, ffix, ppt_vmcs, &pt_decode_vmcs); + ptu_run_fp(suite, fetch_type, ffix, ppt_mnt, &pt_decode_mnt); + ptu_run_fp(suite, fetch_type, ffix, ppt_exstop, &pt_decode_exstop); + ptu_run_fp(suite, fetch_type, ffix, ppt_mwait, &pt_decode_mwait); + ptu_run_fp(suite, fetch_type, ffix, ppt_pwre, &pt_decode_pwre); + ptu_run_fp(suite, fetch_type, ffix, ppt_pwrx, &pt_decode_pwrx); + ptu_run_fp(suite, fetch_type, ffix, ppt_ptw, &pt_decode_ptw); + + ptu_run_f(suite, fetch_tnt_8, ffix); + ptu_run_f(suite, fetch_mode_exec, ffix); + ptu_run_f(suite, fetch_mode_tsx, ffix); + ptu_run_f(suite, fetch_exstop_ip, ffix); + + return ptunit_report(&suite); +} + + +/* Dummy decode functions to satisfy link dependencies. + * + * As a nice side-effect, we will know if we need to add more tests when + * adding new decoder functions. + */ +int pt_pkt_decode_unknown(struct pt_packet_decoder *d, struct pt_packet *p) +{ + (void) d; + (void) p; + + return -pte_internal; +} +int pt_qry_decode_unknown(struct pt_query_decoder *d) +{ + (void) d; + + return -pte_internal; +} + +int pt_pkt_decode_pad(struct pt_packet_decoder *d, struct pt_packet *p) +{ + (void) d; + (void) p; + + return -pte_internal; +} +int pt_qry_decode_pad(struct pt_query_decoder *d) +{ + (void) d; + + return -pte_internal; +} + +int pt_pkt_decode_psb(struct pt_packet_decoder *d, struct pt_packet *p) +{ + (void) d; + (void) p; + + return -pte_internal; +} +int pt_qry_decode_psb(struct pt_query_decoder *d) +{ + (void) d; + + return -pte_internal; +} + +int pt_pkt_decode_tip(struct pt_packet_decoder *d, struct pt_packet *p) +{ + (void) d; + (void) p; + + return -pte_internal; +} +int pt_qry_decode_tip(struct pt_query_decoder *d) +{ + (void) d; + + return -pte_internal; +} + +int pt_pkt_decode_tnt_8(struct pt_packet_decoder *d, struct pt_packet *p) +{ + (void) d; + (void) p; + + return -pte_internal; +} +int pt_qry_decode_tnt_8(struct pt_query_decoder *d) +{ + (void) d; + + return -pte_internal; +} + +int pt_pkt_decode_tnt_64(struct pt_packet_decoder *d, struct pt_packet *p) +{ + (void) d; + (void) p; + + return -pte_internal; +} +int pt_qry_decode_tnt_64(struct pt_query_decoder *d) +{ + (void) d; + + return -pte_internal; +} + +int pt_pkt_decode_tip_pge(struct pt_packet_decoder *d, struct pt_packet *p) +{ + (void) d; + (void) p; + + return -pte_internal; +} +int pt_qry_decode_tip_pge(struct pt_query_decoder *d) +{ + (void) d; + + return -pte_internal; +} + +int pt_pkt_decode_tip_pgd(struct pt_packet_decoder *d, struct pt_packet *p) +{ + (void) d; + (void) p; + + return -pte_internal; +} +int pt_qry_decode_tip_pgd(struct pt_query_decoder *d) +{ + (void) d; + + return -pte_internal; +} + +int pt_pkt_decode_fup(struct pt_packet_decoder *d, struct pt_packet *p) +{ + (void) d; + (void) p; + + return -pte_internal; +} +int pt_qry_decode_fup(struct pt_query_decoder *d) +{ + (void) d; + + return -pte_internal; +} +int pt_qry_header_fup(struct pt_query_decoder *d) +{ + (void) d; + + return -pte_internal; +} + +int pt_pkt_decode_pip(struct pt_packet_decoder *d, struct pt_packet *p) +{ + (void) d; + (void) p; + + return -pte_internal; +} +int pt_qry_decode_pip(struct pt_query_decoder *d) +{ + (void) d; + + return -pte_internal; +} +int pt_qry_header_pip(struct pt_query_decoder *d) +{ + (void) d; + + return -pte_internal; +} + +int pt_pkt_decode_ovf(struct pt_packet_decoder *d, struct pt_packet *p) +{ + (void) d; + (void) p; + + return -pte_internal; +} +int pt_qry_decode_ovf(struct pt_query_decoder *d) +{ + (void) d; + + return -pte_internal; +} + +int pt_pkt_decode_mode(struct pt_packet_decoder *d, struct pt_packet *p) +{ + (void) d; + (void) p; + + return -pte_internal; +} +int pt_qry_decode_mode(struct pt_query_decoder *d) +{ + (void) d; + + return -pte_internal; +} +int pt_qry_header_mode(struct pt_query_decoder *d) +{ + (void) d; + + return -pte_internal; +} + +int pt_pkt_decode_psbend(struct pt_packet_decoder *d, struct pt_packet *p) +{ + (void) d; + (void) p; + + return -pte_internal; +} +int pt_qry_decode_psbend(struct pt_query_decoder *d) +{ + (void) d; + + return -pte_internal; +} + +int pt_pkt_decode_tsc(struct pt_packet_decoder *d, struct pt_packet *p) +{ + (void) d; + (void) p; + + return -pte_internal; +} +int pt_qry_decode_tsc(struct pt_query_decoder *d) +{ + (void) d; + + return -pte_internal; +} +int pt_qry_header_tsc(struct pt_query_decoder *d) +{ + (void) d; + + return -pte_internal; +} + +int pt_pkt_decode_cbr(struct pt_packet_decoder *d, struct pt_packet *p) +{ + (void) d; + (void) p; + + return -pte_internal; +} +int pt_qry_decode_cbr(struct pt_query_decoder *d) +{ + (void) d; + + return -pte_internal; +} +int pt_qry_header_cbr(struct pt_query_decoder *d) +{ + (void) d; + + return -pte_internal; +} + +int pt_pkt_decode_tma(struct pt_packet_decoder *d, struct pt_packet *p) +{ + (void) d; + (void) p; + + return -pte_internal; +} +int pt_qry_decode_tma(struct pt_query_decoder *d) +{ + (void) d; + + return -pte_internal; +} + +int pt_pkt_decode_mtc(struct pt_packet_decoder *d, struct pt_packet *p) +{ + (void) d; + (void) p; + + return -pte_internal; +} +int pt_qry_decode_mtc(struct pt_query_decoder *d) +{ + (void) d; + + return -pte_internal; +} + +int pt_pkt_decode_cyc(struct pt_packet_decoder *d, struct pt_packet *p) +{ + (void) d; + (void) p; + + return -pte_internal; +} +int pt_qry_decode_cyc(struct pt_query_decoder *d) +{ + (void) d; + + return -pte_internal; +} + +int pt_pkt_decode_stop(struct pt_packet_decoder *d, struct pt_packet *p) +{ + (void) d; + (void) p; + + return -pte_internal; +} +int pt_qry_decode_stop(struct pt_query_decoder *d) +{ + (void) d; + + return -pte_internal; +} + +int pt_pkt_decode_vmcs(struct pt_packet_decoder *d, struct pt_packet *p) +{ + (void) d; + (void) p; + + return -pte_internal; +} +int pt_qry_decode_vmcs(struct pt_query_decoder *d) +{ + (void) d; + + return -pte_internal; +} +int pt_qry_header_vmcs(struct pt_query_decoder *d) +{ + (void) d; + + return -pte_internal; +} + +int pt_pkt_decode_mnt(struct pt_packet_decoder *d, struct pt_packet *p) +{ + (void) d; + (void) p; + + return -pte_internal; +} +int pt_qry_decode_mnt(struct pt_query_decoder *d) +{ + (void) d; + + return -pte_internal; +} +int pt_qry_header_mnt(struct pt_query_decoder *d) +{ + (void) d; + + return -pte_internal; +} + +int pt_pkt_decode_exstop(struct pt_packet_decoder *d, struct pt_packet *p) +{ + (void) d; + (void) p; + + return -pte_internal; +} +int pt_qry_decode_exstop(struct pt_query_decoder *d) +{ + (void) d; + + return -pte_internal; +} + +int pt_pkt_decode_mwait(struct pt_packet_decoder *d, struct pt_packet *p) +{ + (void) d; + (void) p; + + return -pte_internal; +} +int pt_qry_decode_mwait(struct pt_query_decoder *d) +{ + (void) d; + + return -pte_internal; +} + +int pt_pkt_decode_pwre(struct pt_packet_decoder *d, struct pt_packet *p) +{ + (void) d; + (void) p; + + return -pte_internal; +} +int pt_qry_decode_pwre(struct pt_query_decoder *d) +{ + (void) d; + + return -pte_internal; +} + +int pt_pkt_decode_pwrx(struct pt_packet_decoder *d, struct pt_packet *p) +{ + (void) d; + (void) p; + + return -pte_internal; +} +int pt_qry_decode_pwrx(struct pt_query_decoder *d) +{ + (void) d; + + return -pte_internal; +} + +int pt_pkt_decode_ptw(struct pt_packet_decoder *d, struct pt_packet *p) +{ + (void) d; + (void) p; + + return -pte_internal; +} +int pt_qry_decode_ptw(struct pt_query_decoder *d) +{ + (void) d; + + return -pte_internal; +} diff --git a/libipt/test/src/ptunit-ild.c b/libipt/test/src/ptunit-ild.c new file mode 100644 index 0000000000000..6c98397df1fbb --- /dev/null +++ b/libipt/test/src/ptunit-ild.c @@ -0,0 +1,757 @@ +/* + * Copyright (c) 2013-2019, Intel Corporation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of Intel Corporation nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "ptunit.h" + +#include "pt_ild.h" + +#include <string.h> + + +/* Check that an instruction is decoded correctly. */ +static struct ptunit_result ptunit_ild_decode(uint8_t *raw, uint8_t size, + enum pt_exec_mode mode) +{ + struct pt_insn_ext iext; + struct pt_insn insn; + int errcode; + + memset(&iext, 0, sizeof(iext)); + memset(&insn, 0, sizeof(insn)); + + memcpy(insn.raw, raw, size); + insn.size = size; + insn.mode = mode; + + errcode = pt_ild_decode(&insn, &iext); + ptu_int_eq(errcode, 0); + + ptu_uint_eq(insn.size, size); + ptu_int_eq(insn.iclass, ptic_other); + ptu_int_eq(iext.iclass, PTI_INST_INVALID); + + return ptu_passed(); +} + +/* Check that an instruction is decoded and classified correctly. */ +static struct ptunit_result ptunit_ild_classify(uint8_t *raw, uint8_t size, + enum pt_exec_mode mode, + pti_inst_enum_t iclass) +{ + struct pt_insn_ext iext; + struct pt_insn insn; + int errcode; + + memset(&iext, 0, sizeof(iext)); + memset(&insn, 0, sizeof(insn)); + + memcpy(insn.raw, raw, size); + insn.size = size; + insn.mode = mode; + + errcode = pt_ild_decode(&insn, &iext); + ptu_int_eq(errcode, 0); + + ptu_uint_eq(insn.size, size); + ptu_int_eq(iext.iclass, iclass); + + return ptu_passed(); +} + +/* Check that an invalid instruction is detected correctly. + * + * Note that we intentionally do not detect all invalid instructions. This test + * therefore only covers some that we care about. + */ +static struct ptunit_result ptunit_ild_invalid(uint8_t *raw, uint8_t size, + enum pt_exec_mode mode) +{ + struct pt_insn_ext iext; + struct pt_insn insn; + int errcode; + + memset(&iext, 0, sizeof(iext)); + memset(&insn, 0, sizeof(insn)); + + memcpy(insn.raw, raw, size); + insn.size = size; + insn.mode = mode; + + errcode = pt_ild_decode(&insn, &iext); + ptu_int_eq(errcode, -pte_bad_insn); + + return ptu_passed(); +} + + +/* Macros to automatically update the test location. */ +#define ptu_decode(insn, size, mode) \ + ptu_check(ptunit_ild_decode, insn, size, mode) + +#define ptu_classify(insn, size, mode, iclass) \ + ptu_check(ptunit_ild_classify, insn, size, mode, iclass) + +/* Macros to also automatically supply the instruction size. */ +#define ptu_decode_s(insn, mode) \ + ptu_decode(insn, sizeof(insn), mode) + +#define ptu_classify_s(insn, mode, iclass) \ + ptu_classify(insn, sizeof(insn), mode, iclass) + +#define ptu_invalid_s(insn, mode) \ + ptu_check(ptunit_ild_invalid, insn, sizeof(insn), mode) + + +static struct ptunit_result push(void) +{ + uint8_t insn[] = { 0x68, 0x11, 0x22, 0x33, 0x44 }; + + ptu_decode_s(insn, ptem_64bit); + + return ptu_passed(); +} + +static struct ptunit_result jmp_rel(void) +{ + uint8_t insn[] = { 0xE9, 0x60, 0xF9, 0xFF, 0xFF }; + + ptu_classify_s(insn, ptem_64bit, PTI_INST_JMP_E9); + + return ptu_passed(); +} + +static struct ptunit_result long_nop(void) +{ + uint8_t insn[] = { 0x66, 0x66, 0x66, 0x66, + 0x66, 0x66, 0X2E, 0X0F, + 0X1F, 0x84, 0x00, 0x00, + 0x00, 0x00, 0x00 }; + + ptu_decode_s(insn, ptem_64bit); + + return ptu_passed(); +} + +static struct ptunit_result mov_al_64(void) +{ + uint8_t insn[] = { 0x48, 0xa0, 0x3f, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, + 0xff, 0x11 }; + + ptu_decode_s(insn, ptem_64bit); + + return ptu_passed(); +} + +static struct ptunit_result mov_al_32_em64(void) +{ + uint8_t insn[] = { 0x67, 0xa0, 0x3f, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, + 0xff, 0X11 }; + + ptu_decode(insn, 6, ptem_64bit); + + return ptu_passed(); +} + +static struct ptunit_result mov_al_32(void) +{ + uint8_t insn[] = { 0xa0, 0x3f, 0xaa, 0xbb, 0xcc, 0xdd, 0xee }; + + ptu_decode(insn, 5, ptem_32bit); + + return ptu_passed(); +} + +static struct ptunit_result mov_al_32_em16(void) +{ + uint8_t insn[] = { 0x67, 0xa0, 0x3f, 0xaa, 0xbb, 0xcc, 0xdd, 0xee }; + + ptu_decode(insn, 6, ptem_16bit); + + return ptu_passed(); +} + +static struct ptunit_result mov_al_16_em32(void) +{ + uint8_t insn[] = { 0x67, 0xa0, 0x3f, 0xaa, 0xbb, 0xcc, 0xdd, 0xee }; + + ptu_decode(insn, 4, ptem_32bit); + + return ptu_passed(); +} + +static struct ptunit_result mov_al_16(void) +{ + uint8_t insn[] = { 0xa0, 0x3f, 0xaa, 0xbb, 0xcc, 0xdd, 0xee }; + + ptu_decode(insn, 3, ptem_16bit); + + return ptu_passed(); +} + +static struct ptunit_result rdtsc(void) +{ + uint8_t insn[] = { 0x0f, 0x31 }; + + ptu_decode_s(insn, ptem_64bit); + + return ptu_passed(); +} + +static struct ptunit_result pcmpistri(void) +{ + uint8_t insn[] = { 0x66, 0x0f, 0x3a, 0x63, 0x04, 0x16, 0x1a }; + + ptu_decode_s(insn, ptem_64bit); + + return ptu_passed(); +} + +static struct ptunit_result vmovdqa(void) +{ + uint8_t insn[] = { 0xc5, 0xf9, 0x6f, 0x25, 0xa9, 0x55, 0x04, 0x00 }; + + ptu_decode_s(insn, ptem_64bit); + + return ptu_passed(); +} + +static struct ptunit_result vpandn(void) +{ + uint8_t insn[] = { 0xc4, 0x41, 0x29, 0xdf, 0xd1 }; + + ptu_decode_s(insn, ptem_64bit); + + return ptu_passed(); +} + +static struct ptunit_result syscall(void) +{ + uint8_t insn[] = { 0x0f, 0x05 }; + + ptu_classify_s(insn, ptem_64bit, PTI_INST_SYSCALL); + + return ptu_passed(); +} + +static struct ptunit_result sysret(void) +{ + uint8_t insn[] = { 0x0f, 0x07 }; + + ptu_classify_s(insn, ptem_64bit, PTI_INST_SYSRET); + + return ptu_passed(); +} + +static struct ptunit_result sysenter(void) +{ + uint8_t insn[] = { 0x0f, 0x34 }; + + ptu_classify_s(insn, ptem_64bit, PTI_INST_SYSENTER); + + return ptu_passed(); +} + +static struct ptunit_result sysexit(void) +{ + uint8_t insn[] = { 0x0f, 0x35 }; + + ptu_classify_s(insn, ptem_64bit, PTI_INST_SYSEXIT); + + return ptu_passed(); +} + +static struct ptunit_result int3(void) +{ + uint8_t insn[] = { 0xcc }; + + ptu_classify_s(insn, ptem_64bit, PTI_INST_INT3); + + return ptu_passed(); +} + +static struct ptunit_result intn(void) +{ + uint8_t insn[] = { 0xcd, 0x06 }; + + ptu_classify_s(insn, ptem_64bit, PTI_INST_INT); + + return ptu_passed(); +} + +static struct ptunit_result iret(void) +{ + uint8_t insn[] = { 0xcf }; + + ptu_classify_s(insn, ptem_64bit, PTI_INST_IRET); + + return ptu_passed(); +} + +static struct ptunit_result call_9a_cd(void) +{ + uint8_t insn[] = { 0x9a, 0x00, 0x00, 0x00, 0x00 }; + + ptu_classify_s(insn, ptem_16bit, PTI_INST_CALL_9A); + + return ptu_passed(); +} + +static struct ptunit_result call_9a_cp(void) +{ + uint8_t insn[] = { 0x9a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + + ptu_classify_s(insn, ptem_32bit, PTI_INST_CALL_9A); + + return ptu_passed(); +} + +static struct ptunit_result call_ff_3(void) +{ + uint8_t insn[] = { 0xff, 0x1c, 0x25, 0x00, 0x00, 0x00, 0x00 }; + + ptu_classify_s(insn, ptem_64bit, PTI_INST_CALL_FFr3); + + return ptu_passed(); +} + +static struct ptunit_result jmp_ff_5(void) +{ + uint8_t insn[] = { 0xff, 0x2c, 0x25, 0x00, 0x00, 0x00, 0x00 }; + + ptu_classify_s(insn, ptem_64bit, PTI_INST_JMP_FFr5); + + return ptu_passed(); +} + +static struct ptunit_result jmp_ea_cd(void) +{ + uint8_t insn[] = { 0xea, 0x00, 0x00, 0x00, 0x00 }; + + ptu_classify_s(insn, ptem_16bit, PTI_INST_JMP_EA); + + return ptu_passed(); +} + +static struct ptunit_result jmp_ea_cp(void) +{ + uint8_t insn[] = { 0xea, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + + ptu_classify_s(insn, ptem_32bit, PTI_INST_JMP_EA); + + return ptu_passed(); +} + +static struct ptunit_result ret_ca(void) +{ + uint8_t insn[] = { 0xca, 0x00, 0x00 }; + + ptu_classify_s(insn, ptem_64bit, PTI_INST_RET_CA); + + return ptu_passed(); +} + +static struct ptunit_result vmlaunch(void) +{ + uint8_t insn[] = { 0x0f, 0x01, 0xc2 }; + + ptu_classify_s(insn, ptem_64bit, PTI_INST_VMLAUNCH); + + return ptu_passed(); +} + +static struct ptunit_result vmresume(void) +{ + uint8_t insn[] = { 0x0f, 0x01, 0xc3 }; + + ptu_classify_s(insn, ptem_64bit, PTI_INST_VMRESUME); + + return ptu_passed(); +} + +static struct ptunit_result vmcall(void) +{ + uint8_t insn[] = { 0x0f, 0x01, 0xc1 }; + + ptu_classify_s(insn, ptem_64bit, PTI_INST_VMCALL); + + return ptu_passed(); +} + +static struct ptunit_result vmptrld(void) +{ + uint8_t insn[] = { 0x0f, 0xc7, 0x30 }; + + ptu_classify_s(insn, ptem_64bit, PTI_INST_VMPTRLD); + + return ptu_passed(); +} + +static struct ptunit_result jrcxz(void) +{ + uint8_t insn[] = { 0xe3, 0x00 }; + + ptu_classify_s(insn, ptem_64bit, PTI_INST_JrCXZ); + + return ptu_passed(); +} + +static struct ptunit_result mov_eax_moffs64(void) +{ + uint8_t insn[] = { 0xa1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00 }; + + ptu_decode_s(insn, ptem_64bit); + + return ptu_passed(); +} + +static struct ptunit_result mov_eax_moffs64_32(void) +{ + uint8_t insn[] = { 0x67, 0xa1, 0x00, 0x00, 0x00, 0x00 }; + + ptu_decode_s(insn, ptem_64bit); + + return ptu_passed(); +} + +static struct ptunit_result mov_rax_moffs64(void) +{ + uint8_t insn[] = { 0x48, 0xa1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00 }; + + ptu_decode_s(insn, ptem_64bit); + + return ptu_passed(); +} + +static struct ptunit_result mov_rax_moffs64_32(void) +{ + uint8_t insn[] = { 0x67, 0x48, 0xa1, 0x00, 0x00, 0x00, 0x00 }; + + ptu_decode_s(insn, ptem_64bit); + + return ptu_passed(); +} + +static struct ptunit_result mov_ax_moffs64(void) +{ + uint8_t insn[] = { 0x66, 0xa1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00 }; + + ptu_decode_s(insn, ptem_64bit); + + return ptu_passed(); +} + +static struct ptunit_result mov_ax_moffs64_32(void) +{ + uint8_t insn[] = { 0x67, 0x66, 0xa1, 0x00, 0x00, 0x00, 0x00 }; + + ptu_decode_s(insn, ptem_64bit); + + return ptu_passed(); +} + +static struct ptunit_result mov_eax_moffs32(void) +{ + uint8_t insn[] = { 0xa1, 0x00, 0x00, 0x00, 0x00 }; + + ptu_decode_s(insn, ptem_32bit); + + return ptu_passed(); +} + +static struct ptunit_result mov_ax_moffs32(void) +{ + uint8_t insn[] = { 0x66, 0xa1, 0x00, 0x00, 0x00, 0x00 }; + + ptu_decode_s(insn, ptem_32bit); + + return ptu_passed(); +} + +static struct ptunit_result mov_ax_moffs16(void) +{ + uint8_t insn[] = { 0xa1, 0x00, 0x00 }; + + ptu_decode_s(insn, ptem_16bit); + + return ptu_passed(); +} + +static struct ptunit_result les(void) +{ + uint8_t insn[] = { 0xc4, 0x00 }; + + ptu_decode_s(insn, ptem_16bit); + ptu_decode_s(insn, ptem_32bit); + + return ptu_passed(); +} + +static struct ptunit_result les_disp16(void) +{ + uint8_t insn[] = { 0xc4, 0x06, 0x00, 0x00 }; + + ptu_decode_s(insn, ptem_16bit); + + return ptu_passed(); +} + +static struct ptunit_result les_disp32(void) +{ + uint8_t insn[] = { 0xc4, 0x05, 0x00, 0x00, 0x00, 0x00 }; + + ptu_decode_s(insn, ptem_32bit); + + return ptu_passed(); +} + +static struct ptunit_result les_ind_disp8(void) +{ + uint8_t insn[] = { 0xc4, 0x40, 0x00 }; + + ptu_decode_s(insn, ptem_16bit); + ptu_decode_s(insn, ptem_32bit); + + return ptu_passed(); +} + +static struct ptunit_result les_ind_disp16(void) +{ + uint8_t insn[] = { 0xc4, 0x80, 0x00, 0x00 }; + + ptu_decode_s(insn, ptem_16bit); + + return ptu_passed(); +} + +static struct ptunit_result les_ind_disp32(void) +{ + uint8_t insn[] = { 0xc4, 0x80, 0x00, 0x00, 0x00, 0x00 }; + + ptu_decode_s(insn, ptem_32bit); + + return ptu_passed(); +} + +static struct ptunit_result lds(void) +{ + uint8_t insn[] = { 0xc5, 0x00 }; + + ptu_decode_s(insn, ptem_16bit); + ptu_decode_s(insn, ptem_32bit); + + return ptu_passed(); +} + +static struct ptunit_result lds_disp16(void) +{ + uint8_t insn[] = { 0xc5, 0x06, 0x00, 0x00 }; + + ptu_decode_s(insn, ptem_16bit); + + return ptu_passed(); +} + +static struct ptunit_result lds_disp32(void) +{ + uint8_t insn[] = { 0xc5, 0x05, 0x00, 0x00, 0x00, 0x00 }; + + ptu_decode_s(insn, ptem_32bit); + + return ptu_passed(); +} + +static struct ptunit_result lds_ind_disp8(void) +{ + uint8_t insn[] = { 0xc5, 0x40, 0x00 }; + + ptu_decode_s(insn, ptem_16bit); + ptu_decode_s(insn, ptem_32bit); + + return ptu_passed(); +} + +static struct ptunit_result lds_ind_disp16(void) +{ + uint8_t insn[] = { 0xc5, 0x80, 0x00, 0x00 }; + + ptu_decode_s(insn, ptem_16bit); + + return ptu_passed(); +} + +static struct ptunit_result lds_ind_disp32(void) +{ + uint8_t insn[] = { 0xc5, 0x80, 0x00, 0x00, 0x00, 0x00 }; + + ptu_decode_s(insn, ptem_32bit); + + return ptu_passed(); +} + +static struct ptunit_result vpshufb(void) +{ + uint8_t insn[] = { 0x62, 0x02, 0x05, 0x00, 0x00, 0x00 }; + + ptu_decode_s(insn, ptem_64bit); + + return ptu_passed(); +} + +static struct ptunit_result bound(void) +{ + uint8_t insn[] = { 0x62, 0x02 }; + + ptu_decode_s(insn, ptem_32bit); + ptu_decode_s(insn, ptem_16bit); + + return ptu_passed(); +} + +static struct ptunit_result evex_cutoff(void) +{ + uint8_t insn[] = { 0x62 }; + + ptu_invalid_s(insn, ptem_64bit); + ptu_invalid_s(insn, ptem_32bit); + ptu_invalid_s(insn, ptem_16bit); + + return ptu_passed(); +} + +static struct ptunit_result ptwrite_r32(void) +{ + uint8_t insn[] = { 0xf3, 0x0f, 0xae, 0xe7 }; + + ptu_classify_s(insn, ptem_64bit, PTI_INST_PTWRITE); + ptu_classify_s(insn, ptem_32bit, PTI_INST_PTWRITE); + ptu_classify_s(insn, ptem_16bit, PTI_INST_PTWRITE); + + return ptu_passed(); +} + +static struct ptunit_result ptwrite_m32(void) +{ + uint8_t insn[] = { 0xf3, 0x0f, 0xae, 0x67, 0xcc }; + + ptu_classify_s(insn, ptem_64bit, PTI_INST_PTWRITE); + ptu_classify_s(insn, ptem_32bit, PTI_INST_PTWRITE); + ptu_classify_s(insn, ptem_16bit, PTI_INST_PTWRITE); + + return ptu_passed(); +} + +static struct ptunit_result ptwrite_r64(void) +{ + uint8_t insn[] = { 0xf3, 0x48, 0x0f, 0xae, 0xe7 }; + + ptu_classify_s(insn, ptem_64bit, PTI_INST_PTWRITE); + + return ptu_passed(); +} + +static struct ptunit_result ptwrite_m64(void) +{ + uint8_t insn[] = { 0xf3, 0x48, 0x0f, 0xae, 0x67, 0xcc }; + + ptu_classify_s(insn, ptem_64bit, PTI_INST_PTWRITE); + + return ptu_passed(); +} + +int main(int argc, char **argv) +{ + struct ptunit_suite suite; + + suite = ptunit_mk_suite(argc, argv); + + ptu_run(suite, push); + ptu_run(suite, jmp_rel); + ptu_run(suite, long_nop); + ptu_run(suite, mov_al_64); + ptu_run(suite, mov_al_32); + ptu_run(suite, mov_al_32_em64); + ptu_run(suite, mov_al_32_em16); + ptu_run(suite, mov_al_16_em32); + ptu_run(suite, mov_al_16); + ptu_run(suite, rdtsc); + ptu_run(suite, pcmpistri); + ptu_run(suite, vmovdqa); + ptu_run(suite, vpandn); + ptu_run(suite, syscall); + ptu_run(suite, sysret); + ptu_run(suite, sysenter); + ptu_run(suite, sysexit); + ptu_run(suite, int3); + ptu_run(suite, intn); + ptu_run(suite, iret); + ptu_run(suite, call_9a_cd); + ptu_run(suite, call_9a_cp); + ptu_run(suite, call_ff_3); + ptu_run(suite, jmp_ff_5); + ptu_run(suite, jmp_ea_cd); + ptu_run(suite, jmp_ea_cp); + ptu_run(suite, ret_ca); + ptu_run(suite, vmlaunch); + ptu_run(suite, vmresume); + ptu_run(suite, vmcall); + ptu_run(suite, vmptrld); + ptu_run(suite, jrcxz); + ptu_run(suite, mov_eax_moffs64); + ptu_run(suite, mov_eax_moffs64_32); + ptu_run(suite, mov_rax_moffs64); + ptu_run(suite, mov_rax_moffs64_32); + ptu_run(suite, mov_ax_moffs64); + ptu_run(suite, mov_ax_moffs64_32); + ptu_run(suite, mov_eax_moffs32); + ptu_run(suite, mov_ax_moffs32); + ptu_run(suite, mov_ax_moffs16); + ptu_run(suite, les); + ptu_run(suite, les_disp16); + ptu_run(suite, les_disp32); + ptu_run(suite, les_ind_disp8); + ptu_run(suite, les_ind_disp16); + ptu_run(suite, les_ind_disp32); + ptu_run(suite, lds); + ptu_run(suite, lds_disp16); + ptu_run(suite, lds_disp32); + ptu_run(suite, lds_ind_disp8); + ptu_run(suite, lds_ind_disp16); + ptu_run(suite, lds_ind_disp32); + ptu_run(suite, vpshufb); + ptu_run(suite, bound); + ptu_run(suite, evex_cutoff); + ptu_run(suite, ptwrite_r32); + ptu_run(suite, ptwrite_m32); + ptu_run(suite, ptwrite_r64); + ptu_run(suite, ptwrite_m64); + + return ptunit_report(&suite); +} diff --git a/libipt/test/src/ptunit-image.c b/libipt/test/src/ptunit-image.c new file mode 100644 index 0000000000000..fb8608996c256 --- /dev/null +++ b/libipt/test/src/ptunit-image.c @@ -0,0 +1,2287 @@ +/* + * Copyright (c) 2013-2019, Intel Corporation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of Intel Corporation nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "ptunit.h" + +#include "pt_image.h" +#include "pt_section.h" +#include "pt_mapped_section.h" + +#include "intel-pt.h" + + +struct image_fixture; + +/* A test mapping. */ +struct ifix_mapping { + /* The contents. */ + uint8_t content[0x10]; + + /* The size - between 0 and sizeof(content). */ + uint64_t size; + + /* An artificial error code to be injected into pt_section_read(). + * + * If @errcode is non-zero, pt_section_read() fails with @errcode. + */ + int errcode; +}; + +/* A test file status - turned into a section status. */ +struct ifix_status { + /* Delete indication: + * - zero if initialized and not (yet) deleted + * - non-zero if deleted and not (re-)initialized + */ + int deleted; + + /* Put with use-count of zero indication. */ + int bad_put; + + /* The test mapping to be used. */ + struct ifix_mapping *mapping; + + /* A link back to the test fixture providing this section. */ + struct image_fixture *ifix; +}; + +enum { + ifix_nsecs = 5 +}; + +/* A fake image section cache. */ +struct pt_image_section_cache { + /* The cached sections. */ + struct pt_section *section[ifix_nsecs]; + + /* Their load addresses. */ + uint64_t laddr[ifix_nsecs]; + + /* The number of used sections. */ + int nsecs; +}; + +extern int pt_iscache_lookup(struct pt_image_section_cache *iscache, + struct pt_section **section, uint64_t *laddr, + int isid); + + +/* A test fixture providing an image, test sections, and asids. */ +struct image_fixture { + /* The image. */ + struct pt_image image; + + /* The test states. */ + struct ifix_status status[ifix_nsecs]; + + /* The test mappings. */ + struct ifix_mapping mapping[ifix_nsecs]; + + /* The sections. */ + struct pt_section section[ifix_nsecs]; + + /* The asids. */ + struct pt_asid asid[3]; + + /* The number of used sections/mappings/states. */ + int nsecs; + + /* An initially empty image as destination for image copies. */ + struct pt_image copy; + + /* A test section cache. */ + struct pt_image_section_cache iscache; + + /* The test fixture initialization and finalization functions. */ + struct ptunit_result (*init)(struct image_fixture *); + struct ptunit_result (*fini)(struct image_fixture *); +}; + +static void ifix_init_section(struct pt_section *section, char *filename, + struct ifix_status *status, + struct ifix_mapping *mapping, + struct image_fixture *ifix) +{ + uint8_t i; + + memset(section, 0, sizeof(*section)); + + section->filename = filename; + section->status = status; + section->size = mapping->size = sizeof(mapping->content); + section->offset = 0x10; + + for (i = 0; i < mapping->size; ++i) + mapping->content[i] = i; + + status->deleted = 0; + status->bad_put = 0; + status->mapping = mapping; + status->ifix = ifix; +} + +static int ifix_add_section(struct image_fixture *ifix, char *filename) +{ + int index; + + if (!ifix) + return -pte_internal; + + index = ifix->nsecs; + if (ifix_nsecs <= index) + return -pte_internal; + + ifix_init_section(&ifix->section[index], filename, &ifix->status[index], + &ifix->mapping[index], ifix); + + ifix->nsecs += 1; + return index; +} + +static int ifix_cache_section(struct image_fixture *ifix, + struct pt_section *section, uint64_t laddr) +{ + int index; + + if (!ifix) + return -pte_internal; + + index = ifix->iscache.nsecs; + if (ifix_nsecs <= index) + return -pte_internal; + + ifix->iscache.section[index] = section; + ifix->iscache.laddr[index] = laddr; + + index += 1; + ifix->iscache.nsecs = index; + + return index; +} + +const char *pt_section_filename(const struct pt_section *section) +{ + if (!section) + return NULL; + + return section->filename; +} + +uint64_t pt_section_offset(const struct pt_section *section) +{ + if (!section) + return 0ull; + + return section->offset; +} + +uint64_t pt_section_size(const struct pt_section *section) +{ + if (!section) + return 0ull; + + return section->size; +} + +int pt_mk_section(struct pt_section **psection, const char *filename, + uint64_t offset, uint64_t size) +{ + (void) psection; + (void) filename; + (void) offset; + (void) size; + + /* This function is not used by our tests. */ + return -pte_not_supported; +} + +int pt_section_get(struct pt_section *section) +{ + if (!section) + return -pte_internal; + + section->ucount += 1; + return 0; +} + +int pt_section_put(struct pt_section *section) +{ + struct ifix_status *status; + uint16_t ucount; + + if (!section) + return -pte_internal; + + status = section->status; + if (!status) + return -pte_internal; + + ucount = section->ucount; + if (!ucount) { + status->bad_put += 1; + + return -pte_internal; + } + + ucount = --section->ucount; + if (!ucount) { + status->deleted += 1; + + if (status->deleted > 1) + return -pte_internal; + } + + return 0; +} + +int pt_iscache_lookup(struct pt_image_section_cache *iscache, + struct pt_section **section, uint64_t *laddr, int isid) +{ + if (!iscache || !section || !laddr) + return -pte_internal; + + if (!isid || iscache->nsecs < isid) + return -pte_bad_image; + + isid -= 1; + + *section = iscache->section[isid]; + *laddr = iscache->laddr[isid]; + + return pt_section_get(*section); +} + +static int ifix_unmap(struct pt_section *section) +{ + uint16_t mcount; + + if (!section) + return -pte_internal; + + mcount = section->mcount; + if (!mcount) + return -pte_internal; + + if (!section->mapping) + return -pte_internal; + + mcount = --section->mcount; + if (!mcount) + section->mapping = NULL; + + return 0; +} + +static int ifix_read(const struct pt_section *section, uint8_t *buffer, + uint16_t size, uint64_t offset) +{ + struct ifix_mapping *mapping; + uint64_t begin, end; + + if (!section || !buffer) + return -pte_internal; + + begin = offset; + end = begin + size; + + if (end < begin) + return -pte_nomap; + + mapping = section->mapping; + if (!mapping) + return -pte_nomap; + + if (mapping->errcode) + return mapping->errcode; + + if (mapping->size <= begin) + return -pte_nomap; + + if (mapping->size < end) { + end = mapping->size; + size = (uint16_t) (end - begin); + } + + memcpy(buffer, &mapping->content[begin], size); + + return size; +} + +int pt_section_map(struct pt_section *section) +{ + struct ifix_status *status; + uint16_t mcount; + + if (!section) + return -pte_internal; + + mcount = section->mcount++; + if (mcount) + return 0; + + if (section->mapping) + return -pte_internal; + + status = section->status; + if (!status) + return -pte_internal; + + section->mapping = status->mapping; + section->unmap = ifix_unmap; + section->read = ifix_read; + + return 0; +} + +int pt_section_on_map_lock(struct pt_section *section) +{ + if (!section) + return -pte_internal; + + return 0; +} + +int pt_section_unmap(struct pt_section *section) +{ + if (!section) + return -pte_internal; + + if (!section->unmap) + return -pte_nomap; + + return section->unmap(section); +} + +int pt_section_read(const struct pt_section *section, uint8_t *buffer, + uint16_t size, uint64_t offset) +{ + if (!section) + return -pte_internal; + + if (!section->read) + return -pte_nomap; + + return section->read(section, buffer, size, offset); +} + +/* A test read memory callback. */ +static int image_readmem_callback(uint8_t *buffer, size_t size, + const struct pt_asid *asid, + uint64_t ip, void *context) +{ + const uint8_t *memory; + size_t idx; + + (void) asid; + + if (!buffer) + return -pte_invalid; + + /* We use a constant offset of 0x3000. */ + if (ip < 0x3000ull) + return -pte_nomap; + + ip -= 0x3000ull; + + memory = (const uint8_t *) context; + if (!memory) + return -pte_internal; + + for (idx = 0; idx < size; ++idx) + buffer[idx] = memory[ip + idx]; + + return (int) idx; +} + +static struct ptunit_result init(void) +{ + struct pt_image image; + + memset(&image, 0xcd, sizeof(image)); + + pt_image_init(&image, NULL); + ptu_null(image.name); + ptu_null(image.sections); + ptu_null((void *) (uintptr_t) image.readmem.callback); + ptu_null(image.readmem.context); + + return ptu_passed(); +} + +static struct ptunit_result init_name(struct image_fixture *ifix) +{ + memset(&ifix->image, 0xcd, sizeof(ifix->image)); + + pt_image_init(&ifix->image, "image-name"); + ptu_str_eq(ifix->image.name, "image-name"); + ptu_null(ifix->image.sections); + ptu_null((void *) (uintptr_t) ifix->image.readmem.callback); + ptu_null(ifix->image.readmem.context); + + return ptu_passed(); +} + +static struct ptunit_result init_null(void) +{ + pt_image_init(NULL, NULL); + + return ptu_passed(); +} + +static struct ptunit_result fini(void) +{ + struct ifix_mapping mapping; + struct ifix_status status; + struct pt_section section; + struct pt_image image; + struct pt_asid asid; + int errcode; + + pt_asid_init(&asid); + ifix_init_section(§ion, NULL, &status, &mapping, NULL); + + pt_image_init(&image, NULL); + errcode = pt_image_add(&image, §ion, &asid, 0x0ull, 0); + ptu_int_eq(errcode, 0); + + pt_image_fini(&image); + ptu_int_eq(section.ucount, 0); + ptu_int_eq(section.mcount, 0); + ptu_int_eq(status.deleted, 1); + ptu_int_eq(status.bad_put, 0); + + return ptu_passed(); +} + +static struct ptunit_result fini_empty(void) +{ + struct pt_image image; + + pt_image_init(&image, NULL); + pt_image_fini(&image); + + return ptu_passed(); +} + +static struct ptunit_result fini_null(void) +{ + pt_image_fini(NULL); + + return ptu_passed(); +} + +static struct ptunit_result name(struct image_fixture *ifix) +{ + const char *name; + + pt_image_init(&ifix->image, "image-name"); + + name = pt_image_name(&ifix->image); + ptu_str_eq(name, "image-name"); + + return ptu_passed(); +} + +static struct ptunit_result name_none(void) +{ + struct pt_image image; + const char *name; + + pt_image_init(&image, NULL); + + name = pt_image_name(&image); + ptu_null(name); + + return ptu_passed(); +} + +static struct ptunit_result name_null(void) +{ + const char *name; + + name = pt_image_name(NULL); + ptu_null(name); + + return ptu_passed(); +} + +static struct ptunit_result read_empty(struct image_fixture *ifix) +{ + struct pt_asid asid; + uint8_t buffer[] = { 0xcc, 0xcc }; + int status, isid; + + pt_asid_init(&asid); + + isid = -1; + status = pt_image_read(&ifix->image, &isid, buffer, sizeof(buffer), + &asid, 0x1000ull); + ptu_int_eq(status, -pte_nomap); + ptu_int_eq(isid, -1); + ptu_uint_eq(buffer[0], 0xcc); + ptu_uint_eq(buffer[1], 0xcc); + + return ptu_passed(); +} + +static struct ptunit_result overlap_front(struct image_fixture *ifix) +{ + uint8_t buffer[] = { 0xcc, 0xcc }; + int status, isid; + + status = pt_image_add(&ifix->image, &ifix->section[0], &ifix->asid[0], + 0x1001ull, 1); + ptu_int_eq(status, 0); + + status = pt_image_add(&ifix->image, &ifix->section[1], &ifix->asid[0], + 0x1000ull, 2); + ptu_int_eq(status, 0); + + isid = -1; + status = pt_image_read(&ifix->image, &isid, buffer, 2, &ifix->asid[0], + 0x1010ull); + ptu_int_eq(status, 1); + ptu_int_eq(isid, 1); + ptu_uint_eq(buffer[0], 0x0f); + ptu_uint_eq(buffer[1], 0xcc); + + buffer[0] = 0xcc; + + isid = -1; + status = pt_image_read(&ifix->image, &isid, buffer, 2, &ifix->asid[0], + 0x100full); + ptu_int_eq(status, 1); + ptu_int_eq(isid, 2); + ptu_uint_eq(buffer[0], 0x0f); + ptu_uint_eq(buffer[1], 0xcc); + + return ptu_passed(); +} + +static struct ptunit_result overlap_back(struct image_fixture *ifix) +{ + uint8_t buffer[] = { 0xcc, 0xcc }; + int status, isid; + + status = pt_image_add(&ifix->image, &ifix->section[0], &ifix->asid[0], + 0x1000ull, 1); + ptu_int_eq(status, 0); + + status = pt_image_add(&ifix->image, &ifix->section[1], &ifix->asid[0], + 0x1001ull, 2); + ptu_int_eq(status, 0); + + isid = -1; + status = pt_image_read(&ifix->image, &isid, buffer, 2, &ifix->asid[0], + 0x1000ull); + ptu_int_eq(status, 1); + ptu_int_eq(isid, 1); + ptu_uint_eq(buffer[0], 0x00); + ptu_uint_eq(buffer[1], 0xcc); + + isid = -1; + status = pt_image_read(&ifix->image, &isid, buffer, 2, &ifix->asid[0], + 0x1010ull); + ptu_int_eq(status, 1); + ptu_int_eq(isid, 2); + ptu_uint_eq(buffer[0], 0x0f); + ptu_uint_eq(buffer[1], 0xcc); + + isid = -1; + status = pt_image_read(&ifix->image, &isid, buffer, 1, &ifix->asid[0], + 0x1001ull); + ptu_int_eq(status, 1); + ptu_int_eq(isid, 2); + ptu_uint_eq(buffer[0], 0x00); + ptu_uint_eq(buffer[1], 0xcc); + + return ptu_passed(); +} + +static struct ptunit_result overlap_multiple(struct image_fixture *ifix) +{ + uint8_t buffer[] = { 0xcc, 0xcc }; + int status, isid; + + status = pt_image_add(&ifix->image, &ifix->section[0], &ifix->asid[0], + 0x1000ull, 1); + ptu_int_eq(status, 0); + + status = pt_image_add(&ifix->image, &ifix->section[0], &ifix->asid[0], + 0x1010ull, 2); + ptu_int_eq(status, 0); + + status = pt_image_add(&ifix->image, &ifix->section[0], &ifix->asid[0], + 0x1008ull, 3); + ptu_int_eq(status, 0); + + isid = -1; + status = pt_image_read(&ifix->image, &isid, buffer, 2, &ifix->asid[0], + 0x1007ull); + ptu_int_eq(status, 1); + ptu_int_eq(isid, 1); + ptu_uint_eq(buffer[0], 0x07); + ptu_uint_eq(buffer[1], 0xcc); + + status = pt_image_read(&ifix->image, &isid, buffer, 1, &ifix->asid[0], + 0x1008ull); + ptu_int_eq(status, 1); + ptu_int_eq(isid, 3); + ptu_uint_eq(buffer[0], 0x00); + ptu_uint_eq(buffer[1], 0xcc); + + isid = -1; + status = pt_image_read(&ifix->image, &isid, buffer, 2, &ifix->asid[0], + 0x1017ull); + ptu_int_eq(status, 1); + ptu_int_eq(isid, 3); + ptu_uint_eq(buffer[0], 0x0f); + ptu_uint_eq(buffer[1], 0xcc); + + isid = -1; + status = pt_image_read(&ifix->image, &isid, buffer, 1, &ifix->asid[0], + 0x1018ull); + ptu_int_eq(status, 1); + ptu_int_eq(isid, 2); + ptu_uint_eq(buffer[0], 0x08); + ptu_uint_eq(buffer[1], 0xcc); + + return ptu_passed(); +} + +static struct ptunit_result overlap_mid(struct image_fixture *ifix) +{ + uint8_t buffer[] = { 0xcc, 0xcc }; + int status, isid; + + status = pt_image_add(&ifix->image, &ifix->section[0], &ifix->asid[0], + 0x1000ull, 1); + ptu_int_eq(status, 0); + + ifix->section[1].size = 0x8; + ifix->mapping[1].size = 0x8; + status = pt_image_add(&ifix->image, &ifix->section[1], &ifix->asid[0], + 0x1004ull, 2); + ptu_int_eq(status, 0); + + isid = -1; + status = pt_image_read(&ifix->image, &isid, buffer, 2, &ifix->asid[0], + 0x1003ull); + ptu_int_eq(status, 1); + ptu_int_eq(isid, 1); + ptu_uint_eq(buffer[0], 0x03); + ptu_uint_eq(buffer[1], 0xcc); + + isid = -1; + status = pt_image_read(&ifix->image, &isid, buffer, 1, &ifix->asid[0], + 0x1004ull); + ptu_int_eq(status, 1); + ptu_int_eq(isid, 2); + ptu_uint_eq(buffer[0], 0x00); + ptu_uint_eq(buffer[1], 0xcc); + + isid = -1; + status = pt_image_read(&ifix->image, &isid, buffer, 2, &ifix->asid[0], + 0x100bull); + ptu_int_eq(status, 1); + ptu_int_eq(isid, 2); + ptu_uint_eq(buffer[0], 0x07); + ptu_uint_eq(buffer[1], 0xcc); + + isid = -1; + status = pt_image_read(&ifix->image, &isid, buffer, 1, &ifix->asid[0], + 0x100cull); + ptu_int_eq(status, 1); + ptu_int_eq(isid, 1); + ptu_uint_eq(buffer[0], 0x0c); + ptu_uint_eq(buffer[1], 0xcc); + + return ptu_passed(); +} + +static struct ptunit_result contained(struct image_fixture *ifix) +{ + uint8_t buffer[] = { 0xcc, 0xcc }; + int status, isid; + + ifix->section[0].size = 0x8; + ifix->mapping[0].size = 0x8; + status = pt_image_add(&ifix->image, &ifix->section[0], &ifix->asid[0], + 0x1004ull, 1); + ptu_int_eq(status, 0); + + status = pt_image_add(&ifix->image, &ifix->section[1], &ifix->asid[0], + 0x1000ull, 2); + ptu_int_eq(status, 0); + + isid = -1; + status = pt_image_read(&ifix->image, &isid, buffer, 1, &ifix->asid[0], + 0x1008ull); + ptu_int_eq(status, 1); + ptu_int_eq(isid, 2); + ptu_uint_eq(buffer[0], 0x08); + ptu_uint_eq(buffer[1], 0xcc); + + return ptu_passed(); +} + +static struct ptunit_result contained_multiple(struct image_fixture *ifix) +{ + uint8_t buffer[] = { 0xcc, 0xcc }; + int status, isid; + + ifix->section[0].size = 0x2; + ifix->mapping[0].size = 0x2; + status = pt_image_add(&ifix->image, &ifix->section[0], &ifix->asid[0], + 0x1004ull, 1); + ptu_int_eq(status, 0); + + status = pt_image_add(&ifix->image, &ifix->section[0], &ifix->asid[0], + 0x1008ull, 2); + ptu_int_eq(status, 0); + + status = pt_image_add(&ifix->image, &ifix->section[1], &ifix->asid[0], + 0x1000ull, 3); + ptu_int_eq(status, 0); + + isid = -1; + status = pt_image_read(&ifix->image, &isid, buffer, 1, &ifix->asid[0], + 0x1004ull); + ptu_int_eq(status, 1); + ptu_int_eq(isid, 3); + ptu_uint_eq(buffer[0], 0x04); + ptu_uint_eq(buffer[1], 0xcc); + + isid = -1; + status = pt_image_read(&ifix->image, &isid, buffer, 1, &ifix->asid[0], + 0x1008ull); + ptu_int_eq(status, 1); + ptu_int_eq(isid, 3); + ptu_uint_eq(buffer[0], 0x08); + ptu_uint_eq(buffer[1], 0xcc); + + return ptu_passed(); +} + +static struct ptunit_result contained_back(struct image_fixture *ifix) +{ + uint8_t buffer[] = { 0xcc, 0xcc }; + int status, isid; + + ifix->section[0].size = 0x8; + ifix->mapping[0].size = 0x8; + status = pt_image_add(&ifix->image, &ifix->section[0], &ifix->asid[0], + 0x1004ull, 1); + ptu_int_eq(status, 0); + + status = pt_image_add(&ifix->image, &ifix->section[0], &ifix->asid[0], + 0x100cull, 2); + ptu_int_eq(status, 0); + + status = pt_image_add(&ifix->image, &ifix->section[1], &ifix->asid[0], + 0x1000ull, 3); + ptu_int_eq(status, 0); + + isid = -1; + status = pt_image_read(&ifix->image, &isid, buffer, 1, &ifix->asid[0], + 0x1004ull); + ptu_int_eq(status, 1); + ptu_int_eq(isid, 3); + ptu_uint_eq(buffer[0], 0x04); + ptu_uint_eq(buffer[1], 0xcc); + + isid = -1; + status = pt_image_read(&ifix->image, &isid, buffer, 1, &ifix->asid[0], + 0x100cull); + ptu_int_eq(status, 1); + ptu_int_eq(isid, 3); + ptu_uint_eq(buffer[0], 0x0c); + ptu_uint_eq(buffer[1], 0xcc); + + isid = -1; + status = pt_image_read(&ifix->image, &isid, buffer, 2, &ifix->asid[0], + 0x100full); + ptu_int_eq(status, 1); + ptu_int_eq(isid, 3); + ptu_uint_eq(buffer[0], 0x0f); + ptu_uint_eq(buffer[1], 0xcc); + + isid = -1; + status = pt_image_read(&ifix->image, &isid, buffer, 1, &ifix->asid[0], + 0x1010ull); + ptu_int_eq(status, 1); + ptu_int_eq(isid, 2); + ptu_uint_eq(buffer[0], 0x04); + ptu_uint_eq(buffer[1], 0xcc); + + return ptu_passed(); +} + +static struct ptunit_result same(struct image_fixture *ifix) +{ + uint8_t buffer[] = { 0xcc, 0xcc }; + int status, isid; + + status = pt_image_add(&ifix->image, &ifix->section[0], &ifix->asid[0], + 0x1000ull, 1); + ptu_int_eq(status, 0); + + status = pt_image_add(&ifix->image, &ifix->section[0], &ifix->asid[0], + 0x1000ull, 1); + ptu_int_eq(status, 0); + + isid = -1; + status = pt_image_read(&ifix->image, &isid, buffer, 1, &ifix->asid[0], + 0x1008ull); + ptu_int_eq(status, 1); + ptu_int_eq(isid, 1); + ptu_uint_eq(buffer[0], 0x08); + ptu_uint_eq(buffer[1], 0xcc); + + return ptu_passed(); +} + +static struct ptunit_result same_different_isid(struct image_fixture *ifix) +{ + uint8_t buffer[] = { 0xcc, 0xcc }; + int status, isid; + + status = pt_image_add(&ifix->image, &ifix->section[0], &ifix->asid[0], + 0x1000ull, 1); + ptu_int_eq(status, 0); + + status = pt_image_add(&ifix->image, &ifix->section[0], &ifix->asid[0], + 0x1000ull, 2); + ptu_int_eq(status, 0); + + isid = -1; + status = pt_image_read(&ifix->image, &isid, buffer, 1, &ifix->asid[0], + 0x1008ull); + ptu_int_eq(status, 1); + ptu_int_eq(isid, 2); + ptu_uint_eq(buffer[0], 0x08); + ptu_uint_eq(buffer[1], 0xcc); + + return ptu_passed(); +} + +static struct ptunit_result same_different_offset(struct image_fixture *ifix) +{ + uint8_t buffer[] = { 0xcc, 0xcc }, i; + int status, isid, index; + + /* Add another section from a different part of the same file as an + * existing section. + */ + index = ifix_add_section(ifix, ifix->section[0].filename); + ptu_int_gt(index, 0); + + ifix->section[index].offset = ifix->section[0].offset + 0x10; + ptu_uint_eq(ifix->section[index].size, ifix->section[0].size); + + /* Change the content of the new section so we can distinguish them. */ + for (i = 0; i < ifix->mapping[index].size; ++i) + ifix->mapping[index].content[i] += 0x10; + + + status = pt_image_add(&ifix->image, &ifix->section[0], &ifix->asid[0], + 0x1000ull, 0); + ptu_int_eq(status, 0); + + status = pt_image_add(&ifix->image, &ifix->section[index], + &ifix->asid[0], 0x1000ull, 0); + ptu_int_eq(status, 0); + + isid = -1; + status = pt_image_read(&ifix->image, &isid, buffer, 1, &ifix->asid[0], + 0x1000ull); + ptu_int_eq(status, 1); + ptu_int_eq(isid, 0); + ptu_uint_eq(buffer[0], 0x10); + ptu_uint_eq(buffer[1], 0xcc); + + isid = -1; + status = pt_image_read(&ifix->image, &isid, buffer, 1, &ifix->asid[0], + 0x100full); + ptu_int_eq(status, 1); + ptu_int_eq(isid, 0); + ptu_uint_eq(buffer[0], 0x1f); + ptu_uint_eq(buffer[1], 0xcc); + + return ptu_passed(); +} + +static struct ptunit_result adjacent(struct image_fixture *ifix) +{ + uint8_t buffer[] = { 0xcc, 0xcc }; + int status, isid; + + status = pt_image_add(&ifix->image, &ifix->section[0], &ifix->asid[0], + 0x1000ull, 1); + ptu_int_eq(status, 0); + + status = pt_image_add(&ifix->image, &ifix->section[1], &ifix->asid[0], + 0x1000ull - ifix->section[1].size, 2); + ptu_int_eq(status, 0); + + status = pt_image_add(&ifix->image, &ifix->section[2], &ifix->asid[0], + 0x1000ull + ifix->section[0].size, 3); + ptu_int_eq(status, 0); + + isid = -1; + status = pt_image_read(&ifix->image, &isid, buffer, 1, &ifix->asid[0], + 0x1000ull); + ptu_int_eq(status, 1); + ptu_int_eq(isid, 1); + ptu_uint_eq(buffer[0], 0x00); + ptu_uint_eq(buffer[1], 0xcc); + + isid = -1; + status = pt_image_read(&ifix->image, &isid, buffer, 1, &ifix->asid[0], + 0xfffull); + ptu_int_eq(status, 1); + ptu_int_eq(isid, 2); + ptu_uint_eq(buffer[0], + ifix->mapping[1].content[ifix->mapping[1].size - 1]); + ptu_uint_eq(buffer[1], 0xcc); + + isid = -1; + status = pt_image_read(&ifix->image, &isid, buffer, 1, &ifix->asid[0], + 0x1000ull + ifix->section[0].size); + ptu_int_eq(status, 1); + ptu_int_eq(isid, 3); + ptu_uint_eq(buffer[0], 0x00); + ptu_uint_eq(buffer[1], 0xcc); + + return ptu_passed(); +} + +static struct ptunit_result read_null(struct image_fixture *ifix) +{ + uint8_t buffer; + int status, isid; + + status = pt_image_read(NULL, &isid, &buffer, 1, &ifix->asid[0], + 0x1000ull); + ptu_int_eq(status, -pte_internal); + + status = pt_image_read(&ifix->image, NULL, &buffer, 1, &ifix->asid[0], + 0x1000ull); + ptu_int_eq(status, -pte_internal); + + status = pt_image_read(&ifix->image, &isid, NULL, 1, &ifix->asid[0], + 0x1000ull); + ptu_int_eq(status, -pte_internal); + + status = pt_image_read(&ifix->image, &isid, &buffer, 1, NULL, + 0x1000ull); + ptu_int_eq(status, -pte_internal); + + return ptu_passed(); +} + +static struct ptunit_result read(struct image_fixture *ifix) +{ + uint8_t buffer[] = { 0xcc, 0xcc, 0xcc }; + int status, isid; + + isid = -1; + status = pt_image_read(&ifix->image, &isid, buffer, 2, &ifix->asid[1], + 0x2003ull); + ptu_int_eq(status, 2); + ptu_int_eq(isid, 11); + ptu_uint_eq(buffer[0], 0x03); + ptu_uint_eq(buffer[1], 0x04); + ptu_uint_eq(buffer[2], 0xcc); + + return ptu_passed(); +} + +static struct ptunit_result read_asid(struct image_fixture *ifix) +{ + uint8_t buffer[] = { 0xcc, 0xcc }; + int status, isid; + + status = pt_image_add(&ifix->image, &ifix->section[0], &ifix->asid[0], + 0x1000ull, 1); + ptu_int_eq(status, 0); + + status = pt_image_add(&ifix->image, &ifix->section[1], &ifix->asid[1], + 0x1008ull, 2); + ptu_int_eq(status, 0); + + isid = -1; + status = pt_image_read(&ifix->image, &isid, buffer, 1, &ifix->asid[0], + 0x1009ull); + ptu_int_eq(status, 1); + ptu_int_eq(isid, 1); + ptu_uint_eq(buffer[0], 0x09); + ptu_uint_eq(buffer[1], 0xcc); + + isid = -1; + status = pt_image_read(&ifix->image, &isid, buffer, 1, &ifix->asid[1], + 0x1009ull); + ptu_int_eq(status, 1); + ptu_int_eq(isid, 2); + ptu_uint_eq(buffer[0], 0x01); + ptu_uint_eq(buffer[1], 0xcc); + + return ptu_passed(); +} + +static struct ptunit_result read_bad_asid(struct image_fixture *ifix) +{ + uint8_t buffer[] = { 0xcc, 0xcc }; + int status, isid; + + isid = -1; + status = pt_image_read(&ifix->image, &isid, buffer, sizeof(buffer), + &ifix->asid[0], 0x2003ull); + ptu_int_eq(status, -pte_nomap); + ptu_int_eq(isid, -1); + ptu_uint_eq(buffer[0], 0xcc); + ptu_uint_eq(buffer[1], 0xcc); + + return ptu_passed(); +} + +static struct ptunit_result read_null_asid(struct image_fixture *ifix) +{ + uint8_t buffer[] = { 0xcc, 0xcc, 0xcc }; + int status, isid; + + isid = -1; + status = pt_image_read(&ifix->image, &isid, buffer, 2, NULL, 0x2003ull); + ptu_int_eq(status, -pte_internal); + ptu_int_eq(isid, -1); + ptu_uint_eq(buffer[0], 0xcc); + ptu_uint_eq(buffer[1], 0xcc); + + return ptu_passed(); +} + +static struct ptunit_result read_callback(struct image_fixture *ifix) +{ + uint8_t memory[] = { 0xdd, 0x01, 0x02, 0xdd }; + uint8_t buffer[] = { 0xcc, 0xcc, 0xcc }; + int status, isid; + + status = pt_image_set_callback(&ifix->image, image_readmem_callback, + memory); + ptu_int_eq(status, 0); + + isid = -1; + status = pt_image_read(&ifix->image, &isid, buffer, 2, &ifix->asid[0], + 0x3001ull); + ptu_int_eq(status, 2); + ptu_int_eq(isid, 0); + ptu_uint_eq(buffer[0], 0x01); + ptu_uint_eq(buffer[1], 0x02); + ptu_uint_eq(buffer[2], 0xcc); + + return ptu_passed(); +} + +static struct ptunit_result read_nomem(struct image_fixture *ifix) +{ + uint8_t buffer[] = { 0xcc, 0xcc }; + int status, isid; + + isid = -1; + status = pt_image_read(&ifix->image, &isid, buffer, sizeof(buffer), + &ifix->asid[1], 0x1010ull); + ptu_int_eq(status, -pte_nomap); + ptu_int_eq(isid, -1); + ptu_uint_eq(buffer[0], 0xcc); + ptu_uint_eq(buffer[1], 0xcc); + + return ptu_passed(); +} + +static struct ptunit_result read_truncated(struct image_fixture *ifix) +{ + uint8_t buffer[] = { 0xcc, 0xcc }; + int status, isid; + + isid = -1; + status = pt_image_read(&ifix->image, &isid, buffer, sizeof(buffer), + &ifix->asid[0], 0x100full); + ptu_int_eq(status, 1); + ptu_int_eq(isid, 10); + ptu_uint_eq(buffer[0], 0x0f); + ptu_uint_eq(buffer[1], 0xcc); + + return ptu_passed(); +} + +static struct ptunit_result read_error(struct image_fixture *ifix) +{ + uint8_t buffer[] = { 0xcc }; + int status, isid; + + ifix->mapping[0].errcode = -pte_nosync; + + isid = -1; + status = pt_image_read(&ifix->image, &isid, buffer, 1, &ifix->asid[0], + 0x1000ull); + ptu_int_eq(status, -pte_nosync); + ptu_int_eq(isid, 10); + ptu_uint_eq(buffer[0], 0xcc); + + return ptu_passed(); +} + +static struct ptunit_result read_spurious_error(struct image_fixture *ifix) +{ + uint8_t buffer[] = { 0xcc, 0xcc }; + int status, isid; + + isid = -1; + status = pt_image_read(&ifix->image, &isid, buffer, 1, &ifix->asid[0], + 0x1000ull); + ptu_int_eq(status, 1); + ptu_int_eq(isid, 10); + ptu_uint_eq(buffer[0], 0x00); + ptu_uint_eq(buffer[1], 0xcc); + + ifix->mapping[0].errcode = -pte_nosync; + + isid = -1; + status = pt_image_read(&ifix->image, &isid, buffer, 1, &ifix->asid[0], + 0x1005ull); + ptu_int_eq(status, -pte_nosync); + ptu_int_eq(isid, 10); + ptu_uint_eq(buffer[0], 0x00); + + return ptu_passed(); +} + +static struct ptunit_result remove_section(struct image_fixture *ifix) +{ + uint8_t buffer[] = { 0xcc, 0xcc, 0xcc }; + int status, isid; + + isid = -1; + status = pt_image_read(&ifix->image, &isid, buffer, 2, &ifix->asid[0], + 0x1001ull); + ptu_int_eq(status, 2); + ptu_int_eq(isid, 10); + ptu_uint_eq(buffer[0], 0x01); + ptu_uint_eq(buffer[1], 0x02); + ptu_uint_eq(buffer[2], 0xcc); + + status = pt_image_remove(&ifix->image, &ifix->section[0], + &ifix->asid[0], 0x1000ull); + ptu_int_eq(status, 0); + + ptu_int_ne(ifix->status[0].deleted, 0); + ptu_int_eq(ifix->status[1].deleted, 0); + + isid = -1; + status = pt_image_read(&ifix->image, &isid, buffer, sizeof(buffer), + &ifix->asid[0], 0x1003ull); + ptu_int_eq(status, -pte_nomap); + ptu_int_eq(isid, -1); + ptu_uint_eq(buffer[0], 0x01); + ptu_uint_eq(buffer[1], 0x02); + ptu_uint_eq(buffer[2], 0xcc); + + isid = -1; + status = pt_image_read(&ifix->image, &isid, buffer, 2, &ifix->asid[1], + 0x2003ull); + ptu_int_eq(status, 2); + ptu_int_eq(isid, 11); + ptu_uint_eq(buffer[0], 0x03); + ptu_uint_eq(buffer[1], 0x04); + ptu_uint_eq(buffer[2], 0xcc); + + return ptu_passed(); +} + +static struct ptunit_result remove_bad_vaddr(struct image_fixture *ifix) +{ + uint8_t buffer[] = { 0xcc, 0xcc, 0xcc }; + int status, isid; + + isid = -1; + status = pt_image_read(&ifix->image, &isid, buffer, 2, &ifix->asid[0], + 0x1001ull); + ptu_int_eq(status, 2); + ptu_int_eq(isid, 10); + ptu_uint_eq(buffer[0], 0x01); + ptu_uint_eq(buffer[1], 0x02); + ptu_uint_eq(buffer[2], 0xcc); + + status = pt_image_remove(&ifix->image, &ifix->section[0], + &ifix->asid[0], 0x2000ull); + ptu_int_eq(status, -pte_bad_image); + + ptu_int_eq(ifix->status[0].deleted, 0); + ptu_int_eq(ifix->status[1].deleted, 0); + + isid = -1; + status = pt_image_read(&ifix->image, &isid, buffer, 2, &ifix->asid[0], + 0x1003ull); + ptu_int_eq(status, 2); + ptu_int_eq(isid, 10); + ptu_uint_eq(buffer[0], 0x03); + ptu_uint_eq(buffer[1], 0x04); + ptu_uint_eq(buffer[2], 0xcc); + + isid = -1; + status = pt_image_read(&ifix->image, &isid, buffer, 2, &ifix->asid[1], + 0x2005ull); + ptu_int_eq(status, 2); + ptu_int_eq(isid, 11); + ptu_uint_eq(buffer[0], 0x05); + ptu_uint_eq(buffer[1], 0x06); + ptu_uint_eq(buffer[2], 0xcc); + + return ptu_passed(); +} + +static struct ptunit_result remove_bad_asid(struct image_fixture *ifix) +{ + uint8_t buffer[] = { 0xcc, 0xcc, 0xcc }; + int status, isid; + + isid = -1; + status = pt_image_read(&ifix->image, &isid, buffer, 2, &ifix->asid[0], + 0x1001ull); + ptu_int_eq(status, 2); + ptu_int_eq(isid, 10); + ptu_uint_eq(buffer[0], 0x01); + ptu_uint_eq(buffer[1], 0x02); + ptu_uint_eq(buffer[2], 0xcc); + + status = pt_image_remove(&ifix->image, &ifix->section[0], + &ifix->asid[1], 0x1000ull); + ptu_int_eq(status, -pte_bad_image); + + ptu_int_eq(ifix->status[0].deleted, 0); + ptu_int_eq(ifix->status[1].deleted, 0); + + isid = -1; + status = pt_image_read(&ifix->image, &isid, buffer, 2, &ifix->asid[0], + 0x1003ull); + ptu_int_eq(status, 2); + ptu_int_eq(isid, 10); + ptu_uint_eq(buffer[0], 0x03); + ptu_uint_eq(buffer[1], 0x04); + ptu_uint_eq(buffer[2], 0xcc); + + isid = -1; + status = pt_image_read(&ifix->image, &isid, buffer, 2, &ifix->asid[1], + 0x2005ull); + ptu_int_eq(status, 2); + ptu_int_eq(isid, 11); + ptu_uint_eq(buffer[0], 0x05); + ptu_uint_eq(buffer[1], 0x06); + ptu_uint_eq(buffer[2], 0xcc); + + return ptu_passed(); +} + +static struct ptunit_result remove_by_filename(struct image_fixture *ifix) +{ + uint8_t buffer[] = { 0xcc, 0xcc, 0xcc }; + int status, isid; + + isid = -1; + status = pt_image_read(&ifix->image, &isid, buffer, 2, &ifix->asid[0], + 0x1001ull); + ptu_int_eq(status, 2); + ptu_int_eq(isid, 10); + ptu_uint_eq(buffer[0], 0x01); + ptu_uint_eq(buffer[1], 0x02); + ptu_uint_eq(buffer[2], 0xcc); + + status = pt_image_remove_by_filename(&ifix->image, + ifix->section[0].filename, + &ifix->asid[0]); + ptu_int_eq(status, 1); + + ptu_int_ne(ifix->status[0].deleted, 0); + ptu_int_eq(ifix->status[1].deleted, 0); + + isid = -1; + status = pt_image_read(&ifix->image, &isid, buffer, sizeof(buffer), + &ifix->asid[0], 0x1003ull); + ptu_int_eq(status, -pte_nomap); + ptu_int_eq(isid, -1); + ptu_uint_eq(buffer[0], 0x01); + ptu_uint_eq(buffer[1], 0x02); + ptu_uint_eq(buffer[2], 0xcc); + + isid = -1; + status = pt_image_read(&ifix->image, &isid, buffer, 2, &ifix->asid[1], + 0x2003ull); + ptu_int_eq(status, 2); + ptu_int_eq(isid, 11); + ptu_uint_eq(buffer[0], 0x03); + ptu_uint_eq(buffer[1], 0x04); + ptu_uint_eq(buffer[2], 0xcc); + + return ptu_passed(); +} + +static struct ptunit_result +remove_by_filename_bad_asid(struct image_fixture *ifix) +{ + uint8_t buffer[] = { 0xcc, 0xcc, 0xcc }; + int status, isid; + + isid = -1; + status = pt_image_read(&ifix->image, &isid, buffer, 2, &ifix->asid[0], + 0x1001ull); + ptu_int_eq(status, 2); + ptu_int_eq(isid, 10); + ptu_uint_eq(buffer[0], 0x01); + ptu_uint_eq(buffer[1], 0x02); + ptu_uint_eq(buffer[2], 0xcc); + + status = pt_image_remove_by_filename(&ifix->image, + ifix->section[0].filename, + &ifix->asid[1]); + ptu_int_eq(status, 0); + + ptu_int_eq(ifix->status[0].deleted, 0); + ptu_int_eq(ifix->status[1].deleted, 0); + + isid = -1; + status = pt_image_read(&ifix->image, &isid, buffer, 2, &ifix->asid[0], + 0x1003ull); + ptu_int_eq(status, 2); + ptu_int_eq(isid, 10); + ptu_uint_eq(buffer[0], 0x03); + ptu_uint_eq(buffer[1], 0x04); + ptu_uint_eq(buffer[2], 0xcc); + + isid = -1; + status = pt_image_read(&ifix->image, &isid, buffer, 2, &ifix->asid[1], + 0x2005ull); + ptu_int_eq(status, 2); + ptu_int_eq(isid, 11); + ptu_uint_eq(buffer[0], 0x05); + ptu_uint_eq(buffer[1], 0x06); + ptu_uint_eq(buffer[2], 0xcc); + + return ptu_passed(); +} + +static struct ptunit_result remove_none_by_filename(struct image_fixture *ifix) +{ + uint8_t buffer[] = { 0xcc, 0xcc, 0xcc }; + int status, isid; + + status = pt_image_remove_by_filename(&ifix->image, "bad-name", + &ifix->asid[0]); + ptu_int_eq(status, 0); + + ptu_int_eq(ifix->status[0].deleted, 0); + ptu_int_eq(ifix->status[1].deleted, 0); + + isid = -1; + status = pt_image_read(&ifix->image, &isid, buffer, 2, &ifix->asid[0], + 0x1003ull); + ptu_int_eq(status, 2); + ptu_int_eq(isid, 10); + ptu_uint_eq(buffer[0], 0x03); + ptu_uint_eq(buffer[1], 0x04); + ptu_uint_eq(buffer[2], 0xcc); + + isid = -1; + status = pt_image_read(&ifix->image, &isid, buffer, 2, &ifix->asid[1], + 0x2001ull); + ptu_int_eq(status, 2); + ptu_int_eq(isid, 11); + ptu_uint_eq(buffer[0], 0x01); + ptu_uint_eq(buffer[1], 0x02); + ptu_uint_eq(buffer[2], 0xcc); + + return ptu_passed(); +} + +static struct ptunit_result remove_all_by_filename(struct image_fixture *ifix) +{ + uint8_t buffer[] = { 0xcc, 0xcc, 0xcc }; + int status, isid; + + ifix->section[0].filename = "same-name"; + ifix->section[1].filename = "same-name"; + + status = pt_image_add(&ifix->image, &ifix->section[0], &ifix->asid[0], + 0x1000ull, 1); + ptu_int_eq(status, 0); + + status = pt_image_add(&ifix->image, &ifix->section[1], &ifix->asid[0], + 0x2000ull, 2); + ptu_int_eq(status, 0); + + isid = -1; + status = pt_image_read(&ifix->image, &isid, buffer, 2, &ifix->asid[0], + 0x1001ull); + ptu_int_eq(status, 2); + ptu_int_eq(isid, 1); + ptu_uint_eq(buffer[0], 0x01); + ptu_uint_eq(buffer[1], 0x02); + ptu_uint_eq(buffer[2], 0xcc); + + status = pt_image_remove_by_filename(&ifix->image, "same-name", + &ifix->asid[0]); + ptu_int_eq(status, 2); + + ptu_int_ne(ifix->status[0].deleted, 0); + ptu_int_ne(ifix->status[1].deleted, 0); + + isid = -1; + status = pt_image_read(&ifix->image, &isid, buffer, sizeof(buffer), + &ifix->asid[0], 0x1003ull); + ptu_int_eq(status, -pte_nomap); + ptu_int_eq(isid, -1); + ptu_uint_eq(buffer[0], 0x01); + ptu_uint_eq(buffer[1], 0x02); + ptu_uint_eq(buffer[2], 0xcc); + + isid = -1; + status = pt_image_read(&ifix->image, &isid, buffer, sizeof(buffer), + &ifix->asid[0], 0x2003ull); + ptu_int_eq(status, -pte_nomap); + ptu_int_eq(isid, -1); + ptu_uint_eq(buffer[0], 0x01); + ptu_uint_eq(buffer[1], 0x02); + ptu_uint_eq(buffer[2], 0xcc); + + return ptu_passed(); +} + +static struct ptunit_result remove_by_asid(struct image_fixture *ifix) +{ + uint8_t buffer[] = { 0xcc, 0xcc, 0xcc }; + int status, isid; + + isid = -1; + status = pt_image_read(&ifix->image, &isid, buffer, 2, &ifix->asid[0], + 0x1001ull); + ptu_int_eq(status, 2); + ptu_int_eq(isid, 10); + ptu_uint_eq(buffer[0], 0x01); + ptu_uint_eq(buffer[1], 0x02); + ptu_uint_eq(buffer[2], 0xcc); + + status = pt_image_remove_by_asid(&ifix->image, &ifix->asid[0]); + ptu_int_eq(status, 1); + + ptu_int_ne(ifix->status[0].deleted, 0); + ptu_int_eq(ifix->status[1].deleted, 0); + + isid = -1; + status = pt_image_read(&ifix->image, &isid, buffer, sizeof(buffer), + &ifix->asid[0], 0x1003ull); + ptu_int_eq(status, -pte_nomap); + ptu_int_eq(isid, -1); + ptu_uint_eq(buffer[0], 0x01); + ptu_uint_eq(buffer[1], 0x02); + ptu_uint_eq(buffer[2], 0xcc); + + isid = -1; + status = pt_image_read(&ifix->image, &isid, buffer, 2, &ifix->asid[1], + 0x2003ull); + ptu_int_eq(status, 2); + ptu_int_eq(isid, 11); + ptu_uint_eq(buffer[0], 0x03); + ptu_uint_eq(buffer[1], 0x04); + ptu_uint_eq(buffer[2], 0xcc); + + return ptu_passed(); +} + +static struct ptunit_result copy_empty(struct image_fixture *ifix) +{ + struct pt_asid asid; + uint8_t buffer[] = { 0xcc, 0xcc }; + int status, isid; + + pt_asid_init(&asid); + + status = pt_image_copy(&ifix->copy, &ifix->image); + ptu_int_eq(status, 0); + + isid = -1; + status = pt_image_read(&ifix->copy, &isid, buffer, sizeof(buffer), + &asid, 0x1000ull); + ptu_int_eq(status, -pte_nomap); + ptu_int_eq(isid, -1); + ptu_uint_eq(buffer[0], 0xcc); + ptu_uint_eq(buffer[1], 0xcc); + + return ptu_passed(); +} + +static struct ptunit_result copy(struct image_fixture *ifix) +{ + uint8_t buffer[] = { 0xcc, 0xcc, 0xcc }; + int status, isid; + + status = pt_image_copy(&ifix->copy, &ifix->image); + ptu_int_eq(status, 0); + + isid = -1; + status = pt_image_read(&ifix->copy, &isid, buffer, 2, &ifix->asid[1], + 0x2003ull); + ptu_int_eq(status, 2); + ptu_int_eq(isid, 11); + ptu_uint_eq(buffer[0], 0x03); + ptu_uint_eq(buffer[1], 0x04); + ptu_uint_eq(buffer[2], 0xcc); + + return ptu_passed(); +} + +static struct ptunit_result copy_self(struct image_fixture *ifix) +{ + uint8_t buffer[] = { 0xcc, 0xcc, 0xcc }; + int status, isid; + + status = pt_image_copy(&ifix->image, &ifix->image); + ptu_int_eq(status, 0); + + isid = -1; + status = pt_image_read(&ifix->image, &isid, buffer, 2, &ifix->asid[1], + 0x2003ull); + ptu_int_eq(status, 2); + ptu_int_eq(isid, 11); + ptu_uint_eq(buffer[0], 0x03); + ptu_uint_eq(buffer[1], 0x04); + ptu_uint_eq(buffer[2], 0xcc); + + return ptu_passed(); +} + +static struct ptunit_result copy_shrink(struct image_fixture *ifix) +{ + uint8_t buffer[] = { 0xcc, 0xcc, 0xcc }; + int status, isid; + + status = pt_image_add(&ifix->copy, &ifix->section[1], &ifix->asid[1], + 0x2000ull, 1); + ptu_int_eq(status, 0); + + status = pt_image_copy(&ifix->copy, &ifix->image); + ptu_int_eq(status, 0); + + isid = -1; + status = pt_image_read(&ifix->copy, &isid, buffer, 2, &ifix->asid[1], + 0x2003ull); + ptu_int_eq(status, 2); + ptu_int_eq(isid, 11); + ptu_uint_eq(buffer[0], 0x03); + ptu_uint_eq(buffer[1], 0x04); + ptu_uint_eq(buffer[2], 0xcc); + + return ptu_passed(); +} + +static struct ptunit_result copy_split(struct image_fixture *ifix) +{ + uint8_t buffer[] = { 0xcc, 0xcc }; + int status, isid; + + status = pt_image_add(&ifix->copy, &ifix->section[0], &ifix->asid[0], + 0x2000ull, 1); + ptu_int_eq(status, 0); + + ifix->section[1].size = 0x7; + ifix->mapping[1].size = 0x7; + + status = pt_image_add(&ifix->image, &ifix->section[1], &ifix->asid[0], + 0x2001ull, 2); + ptu_int_eq(status, 0); + + ifix->section[2].size = 0x8; + ifix->mapping[2].size = 0x8; + + status = pt_image_add(&ifix->image, &ifix->section[2], &ifix->asid[0], + 0x2008ull, 3); + ptu_int_eq(status, 0); + + status = pt_image_copy(&ifix->copy, &ifix->image); + ptu_int_eq(status, 0); + + isid = -1; + status = pt_image_read(&ifix->copy, &isid, buffer, 1, &ifix->asid[0], + 0x2003ull); + ptu_int_eq(status, 1); + ptu_int_eq(isid, 2); + ptu_uint_eq(buffer[0], 0x02); + ptu_uint_eq(buffer[1], 0xcc); + + isid = -1; + status = pt_image_read(&ifix->copy, &isid, buffer, 1, &ifix->asid[0], + 0x2009ull); + ptu_int_eq(status, 1); + ptu_int_eq(isid, 3); + ptu_uint_eq(buffer[0], 0x01); + ptu_uint_eq(buffer[1], 0xcc); + + isid = -1; + status = pt_image_read(&ifix->copy, &isid, buffer, 1, &ifix->asid[0], + 0x2000ull); + ptu_int_eq(status, 1); + ptu_int_eq(isid, 1); + ptu_uint_eq(buffer[0], 0x00); + ptu_uint_eq(buffer[1], 0xcc); + + return ptu_passed(); +} + +static struct ptunit_result copy_merge(struct image_fixture *ifix) +{ + uint8_t buffer[] = { 0xcc, 0xcc }; + int status, isid; + + ifix->section[1].size = 0x8; + ifix->mapping[1].size = 0x8; + + status = pt_image_add(&ifix->copy, &ifix->section[1], &ifix->asid[0], + 0x2000ull, 1); + ptu_int_eq(status, 0); + + ifix->section[2].size = 0x8; + ifix->mapping[2].size = 0x8; + + status = pt_image_add(&ifix->copy, &ifix->section[2], &ifix->asid[0], + 0x2008ull, 2); + ptu_int_eq(status, 0); + + status = pt_image_add(&ifix->image, &ifix->section[0], &ifix->asid[0], + 0x2000ull, 3); + ptu_int_eq(status, 0); + + status = pt_image_copy(&ifix->copy, &ifix->image); + ptu_int_eq(status, 0); + + isid = -1; + status = pt_image_read(&ifix->copy, &isid, buffer, 1, &ifix->asid[0], + 0x2003ull); + ptu_int_eq(status, 1); + ptu_int_eq(isid, 3); + ptu_uint_eq(buffer[0], 0x03); + ptu_uint_eq(buffer[1], 0xcc); + + isid = -1; + status = pt_image_read(&ifix->copy, &isid, buffer, 1, &ifix->asid[0], + 0x200aull); + ptu_int_eq(status, 1); + ptu_int_eq(isid, 3); + ptu_uint_eq(buffer[0], 0x0a); + ptu_uint_eq(buffer[1], 0xcc); + + return ptu_passed(); +} + +static struct ptunit_result copy_overlap(struct image_fixture *ifix) +{ + uint8_t buffer[] = { 0xcc, 0xcc }; + int status, isid; + + status = pt_image_add(&ifix->copy, &ifix->section[0], &ifix->asid[0], + 0x2000ull, 1); + ptu_int_eq(status, 0); + + status = pt_image_add(&ifix->copy, &ifix->section[1], &ifix->asid[0], + 0x2010ull, 2); + ptu_int_eq(status, 0); + + status = pt_image_add(&ifix->image, &ifix->section[2], &ifix->asid[0], + 0x2008ull, 3); + ptu_int_eq(status, 0); + + status = pt_image_copy(&ifix->copy, &ifix->image); + ptu_int_eq(status, 0); + + isid = -1; + status = pt_image_read(&ifix->copy, &isid, buffer, 1, &ifix->asid[0], + 0x2003ull); + ptu_int_eq(status, 1); + ptu_int_eq(isid, 1); + ptu_uint_eq(buffer[0], 0x03); + ptu_uint_eq(buffer[1], 0xcc); + + isid = -1; + status = pt_image_read(&ifix->copy, &isid, buffer, 1, &ifix->asid[0], + 0x200aull); + ptu_int_eq(status, 1); + ptu_int_eq(isid, 3); + ptu_uint_eq(buffer[0], 0x02); + ptu_uint_eq(buffer[1], 0xcc); + + isid = -1; + status = pt_image_read(&ifix->copy, &isid, buffer, 1, &ifix->asid[0], + 0x2016ull); + ptu_int_eq(status, 1); + ptu_int_eq(isid, 3); + ptu_uint_eq(buffer[0], 0x0e); + ptu_uint_eq(buffer[1], 0xcc); + + isid = -1; + status = pt_image_read(&ifix->copy, &isid, buffer, 1, &ifix->asid[0], + 0x2019ull); + ptu_int_eq(status, 1); + ptu_int_eq(isid, 2); + ptu_uint_eq(buffer[0], 0x09); + ptu_uint_eq(buffer[1], 0xcc); + + return ptu_passed(); +} + +static struct ptunit_result copy_replace(struct image_fixture *ifix) +{ + uint8_t buffer[] = { 0xcc, 0xcc, 0xcc }; + int status, isid; + + ifix->section[0].size = 0x8; + ifix->mapping[0].size = 0x8; + + status = pt_image_add(&ifix->copy, &ifix->section[0], &ifix->asid[0], + 0x1004ull, 1); + ptu_int_eq(status, 0); + + status = pt_image_add(&ifix->image, &ifix->section[1], &ifix->asid[0], + 0x1000ull, 2); + ptu_int_eq(status, 0); + + status = pt_image_copy(&ifix->copy, &ifix->image); + ptu_int_eq(status, 0); + + isid = -1; + status = pt_image_read(&ifix->copy, &isid, buffer, 2, &ifix->asid[0], + 0x1003ull); + ptu_int_eq(status, 2); + ptu_int_eq(isid, 2); + ptu_uint_eq(buffer[0], 0x03); + ptu_uint_eq(buffer[1], 0x04); + ptu_uint_eq(buffer[2], 0xcc); + + return ptu_passed(); +} + +static struct ptunit_result add_cached_null(void) +{ + struct pt_image_section_cache iscache; + struct pt_image image; + int status; + + status = pt_image_add_cached(NULL, &iscache, 0, NULL); + ptu_int_eq(status, -pte_invalid); + + status = pt_image_add_cached(&image, NULL, 0, NULL); + ptu_int_eq(status, -pte_invalid); + + return ptu_passed(); +} + +static struct ptunit_result add_cached(struct image_fixture *ifix) +{ + uint8_t buffer[] = { 0xcc, 0xcc, 0xcc }; + int status, isid, risid; + + isid = ifix_cache_section(ifix, &ifix->section[0], 0x1000ull); + ptu_int_gt(isid, 0); + + status = pt_image_add_cached(&ifix->image, &ifix->iscache, isid, + &ifix->asid[0]); + ptu_int_eq(status, 0); + + risid = -1; + status = pt_image_read(&ifix->image, &risid, buffer, 2, &ifix->asid[0], + 0x1003ull); + ptu_int_eq(status, 2); + ptu_int_eq(risid, isid); + ptu_uint_eq(buffer[0], 0x03); + ptu_uint_eq(buffer[1], 0x04); + ptu_uint_eq(buffer[2], 0xcc); + + return ptu_passed(); +} + +static struct ptunit_result add_cached_null_asid(struct image_fixture *ifix) +{ + uint8_t buffer[] = { 0xcc, 0xcc, 0xcc }; + int status, isid, risid; + + isid = ifix_cache_section(ifix, &ifix->section[0], 0x1000ull); + ptu_int_gt(isid, 0); + + status = pt_image_add_cached(&ifix->image, &ifix->iscache, isid, NULL); + ptu_int_eq(status, 0); + + risid = -1; + status = pt_image_read(&ifix->image, &risid, buffer, 2, &ifix->asid[0], + 0x1003ull); + ptu_int_eq(status, 2); + ptu_int_eq(risid, isid); + ptu_uint_eq(buffer[0], 0x03); + ptu_uint_eq(buffer[1], 0x04); + ptu_uint_eq(buffer[2], 0xcc); + + return ptu_passed(); +} + +static struct ptunit_result add_cached_twice(struct image_fixture *ifix) +{ + uint8_t buffer[] = { 0xcc, 0xcc, 0xcc }; + int status, isid, risid; + + isid = ifix_cache_section(ifix, &ifix->section[0], 0x1000ull); + ptu_int_gt(isid, 0); + + status = pt_image_add_cached(&ifix->image, &ifix->iscache, isid, + &ifix->asid[0]); + ptu_int_eq(status, 0); + + status = pt_image_add_cached(&ifix->image, &ifix->iscache, isid, + &ifix->asid[0]); + ptu_int_eq(status, 0); + + risid = -1; + status = pt_image_read(&ifix->image, &risid, buffer, 2, &ifix->asid[0], + 0x1003ull); + ptu_int_eq(status, 2); + ptu_int_eq(risid, isid); + ptu_uint_eq(buffer[0], 0x03); + ptu_uint_eq(buffer[1], 0x04); + ptu_uint_eq(buffer[2], 0xcc); + + return ptu_passed(); +} + +static struct ptunit_result add_cached_bad_isid(struct image_fixture *ifix) +{ + uint8_t buffer[] = { 0xcc, 0xcc, 0xcc }; + int status, isid; + + status = pt_image_add_cached(&ifix->image, &ifix->iscache, 1, + &ifix->asid[0]); + ptu_int_eq(status, -pte_bad_image); + + isid = -1; + status = pt_image_read(&ifix->image, &isid, buffer, 2, &ifix->asid[0], + 0x1003ull); + ptu_int_eq(status, -pte_nomap); + ptu_int_eq(isid, -1); + + return ptu_passed(); +} + +static struct ptunit_result find_null(struct image_fixture *ifix) +{ + struct pt_mapped_section msec; + int status; + + status = pt_image_find(NULL, &msec, &ifix->asid[0], + 0x1000ull); + ptu_int_eq(status, -pte_internal); + + status = pt_image_find(&ifix->image, NULL, &ifix->asid[0], + 0x1000ull); + ptu_int_eq(status, -pte_internal); + + status = pt_image_find(&ifix->image, &msec, NULL, 0x1000ull); + ptu_int_eq(status, -pte_internal); + + return ptu_passed(); +} + +static struct ptunit_result find(struct image_fixture *ifix) +{ + struct pt_mapped_section msec; + int status; + + status = pt_image_find(&ifix->image, &msec, &ifix->asid[1], 0x2003ull); + ptu_int_eq(status, 11); + ptu_ptr_eq(msec.section, &ifix->section[1]); + ptu_uint_eq(msec.vaddr, 0x2000ull); + + status = pt_section_put(msec.section); + ptu_int_eq(status, 0); + + return ptu_passed(); +} + +static struct ptunit_result find_asid(struct image_fixture *ifix) +{ + struct pt_mapped_section msec; + int status; + + status = pt_image_add(&ifix->image, &ifix->section[0], &ifix->asid[0], + 0x1000ull, 1); + ptu_int_eq(status, 0); + + status = pt_image_add(&ifix->image, &ifix->section[0], &ifix->asid[1], + 0x1008ull, 2); + ptu_int_eq(status, 0); + + status = pt_image_find(&ifix->image, &msec, &ifix->asid[0], 0x1009ull); + ptu_int_eq(status, 1); + ptu_ptr_eq(msec.section, &ifix->section[0]); + ptu_uint_eq(msec.vaddr, 0x1000ull); + + status = pt_section_put(msec.section); + ptu_int_eq(status, 0); + + status = pt_image_find(&ifix->image, &msec, &ifix->asid[1], 0x1009ull); + ptu_int_eq(status, 2); + ptu_ptr_eq(msec.section, &ifix->section[0]); + ptu_uint_eq(msec.vaddr, 0x1008ull); + + status = pt_section_put(msec.section); + ptu_int_eq(status, 0); + + return ptu_passed(); +} + +static struct ptunit_result find_bad_asid(struct image_fixture *ifix) +{ + struct pt_mapped_section msec; + int status; + + status = pt_image_find(&ifix->image, &msec, &ifix->asid[0], 0x2003ull); + ptu_int_eq(status, -pte_nomap); + + return ptu_passed(); +} + +static struct ptunit_result find_nomem(struct image_fixture *ifix) +{ + struct pt_mapped_section msec; + int status; + + status = pt_image_find(&ifix->image, &msec, &ifix->asid[1], 0x1010ull); + ptu_int_eq(status, -pte_nomap); + + return ptu_passed(); +} + +static struct ptunit_result validate_null(struct image_fixture *ifix) +{ + struct pt_mapped_section msec; + int status; + + status = pt_image_validate(NULL, &msec, 0x1004ull, 10); + ptu_int_eq(status, -pte_internal); + + status = pt_image_validate(&ifix->image, NULL, 0x1004ull, 10); + ptu_int_eq(status, -pte_internal); + + return ptu_passed(); +} + +static struct ptunit_result validate(struct image_fixture *ifix) +{ + struct pt_mapped_section msec; + int isid, status; + + isid = pt_image_find(&ifix->image, &msec, &ifix->asid[0], 0x1003ull); + ptu_int_ge(isid, 0); + + status = pt_section_put(msec.section); + ptu_int_eq(status, 0); + + status = pt_image_validate(&ifix->image, &msec, 0x1004ull, isid); + ptu_int_eq(status, 0); + + return ptu_passed(); +} + +static struct ptunit_result validate_bad_asid(struct image_fixture *ifix) +{ + struct pt_mapped_section msec; + int isid, status; + + isid = pt_image_find(&ifix->image, &msec, &ifix->asid[0], 0x1003ull); + ptu_int_ge(isid, 0); + + status = pt_section_put(msec.section); + ptu_int_eq(status, 0); + + msec.asid = ifix->asid[1]; + + status = pt_image_validate(&ifix->image, &msec, 0x1004ull, isid); + ptu_int_eq(status, -pte_nomap); + + return ptu_passed(); +} + +static struct ptunit_result validate_bad_vaddr(struct image_fixture *ifix) +{ + struct pt_mapped_section msec; + int isid, status; + + isid = pt_image_find(&ifix->image, &msec, &ifix->asid[0], 0x1003ull); + ptu_int_ge(isid, 0); + + status = pt_section_put(msec.section); + ptu_int_eq(status, 0); + + msec.vaddr = 0x2000ull; + + status = pt_image_validate(&ifix->image, &msec, 0x1004ull, isid); + ptu_int_eq(status, -pte_nomap); + + return ptu_passed(); +} + +static struct ptunit_result validate_bad_offset(struct image_fixture *ifix) +{ + struct pt_mapped_section msec; + int isid, status; + + isid = pt_image_find(&ifix->image, &msec, &ifix->asid[0], 0x1003ull); + ptu_int_ge(isid, 0); + + status = pt_section_put(msec.section); + ptu_int_eq(status, 0); + + msec.offset = 0x8ull; + + status = pt_image_validate(&ifix->image, &msec, 0x1004ull, isid); + ptu_int_eq(status, -pte_nomap); + + return ptu_passed(); +} + +static struct ptunit_result validate_bad_size(struct image_fixture *ifix) +{ + struct pt_mapped_section msec; + int isid, status; + + isid = pt_image_find(&ifix->image, &msec, &ifix->asid[0], 0x1003ull); + ptu_int_ge(isid, 0); + + status = pt_section_put(msec.section); + ptu_int_eq(status, 0); + + msec.size = 0x8ull; + + status = pt_image_validate(&ifix->image, &msec, 0x1004ull, isid); + ptu_int_eq(status, -pte_nomap); + + return ptu_passed(); +} + +static struct ptunit_result validate_bad_isid(struct image_fixture *ifix) +{ + struct pt_mapped_section msec; + int isid, status; + + isid = pt_image_find(&ifix->image, &msec, &ifix->asid[0], 0x1003ull); + ptu_int_ge(isid, 0); + + status = pt_section_put(msec.section); + ptu_int_eq(status, 0); + + status = pt_image_validate(&ifix->image, &msec, 0x1004ull, isid + 1); + ptu_int_eq(status, -pte_nomap); + + return ptu_passed(); +} + +static struct ptunit_result ifix_init(struct image_fixture *ifix) +{ + int index; + + pt_image_init(&ifix->image, NULL); + pt_image_init(&ifix->copy, NULL); + + memset(ifix->status, 0, sizeof(ifix->status)); + memset(ifix->mapping, 0, sizeof(ifix->mapping)); + memset(ifix->section, 0, sizeof(ifix->section)); + memset(&ifix->iscache, 0, sizeof(ifix->iscache)); + + ifix->nsecs = 0; + + index = ifix_add_section(ifix, "file-0"); + ptu_int_eq(index, 0); + + index = ifix_add_section(ifix, "file-1"); + ptu_int_eq(index, 1); + + index = ifix_add_section(ifix, "file-2"); + ptu_int_eq(index, 2); + + pt_asid_init(&ifix->asid[0]); + ifix->asid[0].cr3 = 0xa000; + + pt_asid_init(&ifix->asid[1]); + ifix->asid[1].cr3 = 0xb000; + + pt_asid_init(&ifix->asid[2]); + ifix->asid[2].cr3 = 0xc000; + + return ptu_passed(); +} + +static struct ptunit_result rfix_init(struct image_fixture *ifix) +{ + int status; + + ptu_check(ifix_init, ifix); + + status = pt_image_add(&ifix->image, &ifix->section[0], &ifix->asid[0], + 0x1000ull, 10); + ptu_int_eq(status, 0); + + status = pt_image_add(&ifix->image, &ifix->section[1], &ifix->asid[1], + 0x2000ull, 11); + ptu_int_eq(status, 0); + + return ptu_passed(); +} + +static struct ptunit_result dfix_fini(struct image_fixture *ifix) +{ + pt_image_fini(&ifix->image); + + return ptu_passed(); +} + +static struct ptunit_result ifix_fini(struct image_fixture *ifix) +{ + int sec; + + ptu_check(dfix_fini, ifix); + + pt_image_fini(&ifix->copy); + + for (sec = 0; sec < ifix_nsecs; ++sec) { + ptu_int_eq(ifix->section[sec].ucount, 0); + ptu_int_eq(ifix->section[sec].mcount, 0); + ptu_int_le(ifix->status[sec].deleted, 1); + ptu_int_eq(ifix->status[sec].bad_put, 0); + } + + return ptu_passed(); +} + +int main(int argc, char **argv) +{ + struct image_fixture dfix, ifix, rfix; + struct ptunit_suite suite; + + /* Dfix provides image destruction. */ + dfix.init = NULL; + dfix.fini = dfix_fini; + + /* Ifix provides an empty image. */ + ifix.init = ifix_init; + ifix.fini = ifix_fini; + + /* Rfix provides an image with two sections added. */ + rfix.init = rfix_init; + rfix.fini = ifix_fini; + + suite = ptunit_mk_suite(argc, argv); + + ptu_run(suite, init); + ptu_run_f(suite, init_name, dfix); + ptu_run(suite, init_null); + + ptu_run(suite, fini); + ptu_run(suite, fini_empty); + ptu_run(suite, fini_null); + + ptu_run_f(suite, name, dfix); + ptu_run(suite, name_none); + ptu_run(suite, name_null); + + ptu_run_f(suite, read_empty, ifix); + ptu_run_f(suite, overlap_front, ifix); + ptu_run_f(suite, overlap_back, ifix); + ptu_run_f(suite, overlap_multiple, ifix); + ptu_run_f(suite, overlap_mid, ifix); + ptu_run_f(suite, contained, ifix); + ptu_run_f(suite, contained_multiple, ifix); + ptu_run_f(suite, contained_back, ifix); + ptu_run_f(suite, same, ifix); + ptu_run_f(suite, same_different_isid, ifix); + ptu_run_f(suite, same_different_offset, ifix); + ptu_run_f(suite, adjacent, ifix); + + ptu_run_f(suite, read_null, rfix); + ptu_run_f(suite, read, rfix); + ptu_run_f(suite, read_null, rfix); + ptu_run_f(suite, read_asid, ifix); + ptu_run_f(suite, read_bad_asid, rfix); + ptu_run_f(suite, read_null_asid, rfix); + ptu_run_f(suite, read_callback, rfix); + ptu_run_f(suite, read_nomem, rfix); + ptu_run_f(suite, read_truncated, rfix); + ptu_run_f(suite, read_error, rfix); + ptu_run_f(suite, read_spurious_error, rfix); + + ptu_run_f(suite, remove_section, rfix); + ptu_run_f(suite, remove_bad_vaddr, rfix); + ptu_run_f(suite, remove_bad_asid, rfix); + ptu_run_f(suite, remove_by_filename, rfix); + ptu_run_f(suite, remove_by_filename_bad_asid, rfix); + ptu_run_f(suite, remove_none_by_filename, rfix); + ptu_run_f(suite, remove_all_by_filename, ifix); + ptu_run_f(suite, remove_by_asid, rfix); + + ptu_run_f(suite, copy_empty, ifix); + ptu_run_f(suite, copy, rfix); + ptu_run_f(suite, copy_self, rfix); + ptu_run_f(suite, copy_shrink, rfix); + ptu_run_f(suite, copy_split, ifix); + ptu_run_f(suite, copy_merge, ifix); + ptu_run_f(suite, copy_overlap, ifix); + ptu_run_f(suite, copy_replace, ifix); + + ptu_run(suite, add_cached_null); + ptu_run_f(suite, add_cached, ifix); + ptu_run_f(suite, add_cached_null_asid, ifix); + ptu_run_f(suite, add_cached_twice, ifix); + ptu_run_f(suite, add_cached_bad_isid, ifix); + + ptu_run_f(suite, find_null, rfix); + ptu_run_f(suite, find, rfix); + ptu_run_f(suite, find_asid, ifix); + ptu_run_f(suite, find_bad_asid, rfix); + ptu_run_f(suite, find_nomem, rfix); + + ptu_run_f(suite, validate_null, rfix); + ptu_run_f(suite, validate, rfix); + ptu_run_f(suite, validate_bad_asid, rfix); + ptu_run_f(suite, validate_bad_vaddr, rfix); + ptu_run_f(suite, validate_bad_offset, rfix); + ptu_run_f(suite, validate_bad_size, rfix); + ptu_run_f(suite, validate_bad_isid, rfix); + + return ptunit_report(&suite); +} diff --git a/libipt/test/src/ptunit-image_section_cache.c b/libipt/test/src/ptunit-image_section_cache.c new file mode 100644 index 0000000000000..b94e733ae97fa --- /dev/null +++ b/libipt/test/src/ptunit-image_section_cache.c @@ -0,0 +1,2031 @@ +/* + * Copyright (c) 2016-2019, Intel Corporation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of Intel Corporation nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "pt_image_section_cache.h" + +#include "ptunit_threads.h" + +#include "intel-pt.h" + +#include <stdlib.h> + + +struct pt_section { + /* The filename. We only support string literals for testing. */ + const char *filename; + + /* The file offset and size. */ + uint64_t offset; + uint64_t size; + + /* The bcache size. */ + uint64_t bcsize; + + /* The iscache back link. */ + struct pt_image_section_cache *iscache; + + /* The file content. */ + uint8_t content[0x10]; + + /* The use count. */ + int ucount; + + /* The attach count. */ + int acount; + + /* The map count. */ + int mcount; + +#if defined(FEATURE_THREADS) + /* A lock protecting this section. */ + mtx_t lock; + /* A lock protecting the iscache and acount fields. */ + mtx_t alock; +#endif /* defined(FEATURE_THREADS) */ +}; + +extern int pt_mk_section(struct pt_section **psection, const char *filename, + uint64_t offset, uint64_t size); + +extern int pt_section_get(struct pt_section *section); +extern int pt_section_put(struct pt_section *section); +extern int pt_section_attach(struct pt_section *section, + struct pt_image_section_cache *iscache); +extern int pt_section_detach(struct pt_section *section, + struct pt_image_section_cache *iscache); + +extern int pt_section_map(struct pt_section *section); +extern int pt_section_map_share(struct pt_section *section); +extern int pt_section_unmap(struct pt_section *section); +extern int pt_section_request_bcache(struct pt_section *section); + +extern const char *pt_section_filename(const struct pt_section *section); +extern uint64_t pt_section_offset(const struct pt_section *section); +extern uint64_t pt_section_size(const struct pt_section *section); +extern int pt_section_memsize(struct pt_section *section, uint64_t *size); + +extern int pt_section_read(const struct pt_section *section, uint8_t *buffer, + uint16_t size, uint64_t offset); + + +int pt_mk_section(struct pt_section **psection, const char *filename, + uint64_t offset, uint64_t size) +{ + struct pt_section *section; + uint8_t idx; + + section = malloc(sizeof(*section)); + if (!section) + return -pte_nomem; + + memset(section, 0, sizeof(*section)); + section->filename = filename; + section->offset = offset; + section->size = size; + section->ucount = 1; + + for (idx = 0; idx < sizeof(section->content); ++idx) + section->content[idx] = idx; + +#if defined(FEATURE_THREADS) + { + int errcode; + + errcode = mtx_init(§ion->lock, mtx_plain); + if (errcode != thrd_success) { + free(section); + return -pte_bad_lock; + } + + errcode = mtx_init(§ion->alock, mtx_plain); + if (errcode != thrd_success) { + mtx_destroy(§ion->lock); + free(section); + return -pte_bad_lock; + } + } +#endif /* defined(FEATURE_THREADS) */ + + *psection = section; + + return 0; +} + +static int pt_section_lock(struct pt_section *section) +{ + if (!section) + return -pte_internal; + +#if defined(FEATURE_THREADS) + { + int errcode; + + errcode = mtx_lock(§ion->lock); + if (errcode != thrd_success) + return -pte_bad_lock; + } +#endif /* defined(FEATURE_THREADS) */ + + return 0; +} + +static int pt_section_unlock(struct pt_section *section) +{ + if (!section) + return -pte_internal; + +#if defined(FEATURE_THREADS) + { + int errcode; + + errcode = mtx_unlock(§ion->lock); + if (errcode != thrd_success) + return -pte_bad_lock; + } +#endif /* defined(FEATURE_THREADS) */ + + return 0; +} + +static int pt_section_lock_attach(struct pt_section *section) +{ + if (!section) + return -pte_internal; + +#if defined(FEATURE_THREADS) + { + int errcode; + + errcode = mtx_lock(§ion->alock); + if (errcode != thrd_success) + return -pte_bad_lock; + } +#endif /* defined(FEATURE_THREADS) */ + + return 0; +} + +static int pt_section_unlock_attach(struct pt_section *section) +{ + if (!section) + return -pte_internal; + +#if defined(FEATURE_THREADS) + { + int errcode; + + errcode = mtx_unlock(§ion->alock); + if (errcode != thrd_success) + return -pte_bad_lock; + } +#endif /* defined(FEATURE_THREADS) */ + + return 0; +} + +int pt_section_get(struct pt_section *section) +{ + int errcode, ucount; + + if (!section) + return -pte_internal; + + errcode = pt_section_lock(section); + if (errcode < 0) + return errcode; + + ucount = ++section->ucount; + + errcode = pt_section_unlock(section); + if (errcode < 0) + return errcode; + + if (!ucount) + return -pte_internal; + + return 0; +} + +int pt_section_put(struct pt_section *section) +{ + int errcode, ucount; + + if (!section) + return -pte_internal; + + errcode = pt_section_lock(section); + if (errcode < 0) + return errcode; + + ucount = --section->ucount; + + errcode = pt_section_unlock(section); + if (errcode < 0) + return errcode; + + if (!ucount) { +#if defined(FEATURE_THREADS) + mtx_destroy(§ion->alock); + mtx_destroy(§ion->lock); +#endif /* defined(FEATURE_THREADS) */ + free(section); + } + + return 0; +} + +int pt_section_attach(struct pt_section *section, + struct pt_image_section_cache *iscache) +{ + int errcode, ucount, acount; + + if (!section || !iscache) + return -pte_internal; + + errcode = pt_section_lock_attach(section); + if (errcode < 0) + return errcode; + + ucount = section->ucount; + acount = section->acount; + if (!acount) { + if (section->iscache || !ucount) + goto out_unlock; + + section->iscache = iscache; + section->acount = 1; + + return pt_section_unlock_attach(section); + } + + acount += 1; + if (!acount) { + (void) pt_section_unlock_attach(section); + return -pte_overflow; + } + + if (ucount < acount) + goto out_unlock; + + if (section->iscache != iscache) + goto out_unlock; + + section->acount = acount; + + return pt_section_unlock_attach(section); + + out_unlock: + (void) pt_section_unlock_attach(section); + return -pte_internal; +} + +int pt_section_detach(struct pt_section *section, + struct pt_image_section_cache *iscache) +{ + int errcode, ucount, acount; + + if (!section || !iscache) + return -pte_internal; + + errcode = pt_section_lock_attach(section); + if (errcode < 0) + return errcode; + + if (section->iscache != iscache) + goto out_unlock; + + acount = section->acount; + if (!acount) + goto out_unlock; + + acount -= 1; + ucount = section->ucount; + if (ucount < acount) + goto out_unlock; + + section->acount = acount; + if (!acount) + section->iscache = NULL; + + return pt_section_unlock_attach(section); + + out_unlock: + (void) pt_section_unlock_attach(section); + return -pte_internal; +} + +int pt_section_map(struct pt_section *section) +{ + struct pt_image_section_cache *iscache; + int errcode, status; + + if (!section) + return -pte_internal; + + errcode = pt_section_map_share(section); + if (errcode < 0) + return errcode; + + errcode = pt_section_lock_attach(section); + if (errcode < 0) + return errcode; + + status = 0; + iscache = section->iscache; + if (iscache) + status = pt_iscache_notify_map(iscache, section); + + errcode = pt_section_unlock_attach(section); + + return (status < 0) ? status : errcode; +} + +int pt_section_map_share(struct pt_section *section) +{ + int errcode, mcount; + + if (!section) + return -pte_internal; + + errcode = pt_section_lock(section); + if (errcode < 0) + return errcode; + + mcount = ++section->mcount; + + errcode = pt_section_unlock(section); + if (errcode < 0) + return errcode; + + if (mcount <= 0) + return -pte_internal; + + return 0; +} + +int pt_section_unmap(struct pt_section *section) +{ + int errcode, mcount; + + if (!section) + return -pte_internal; + + errcode = pt_section_lock(section); + if (errcode < 0) + return errcode; + + section->bcsize = 0ull; + mcount = --section->mcount; + + errcode = pt_section_unlock(section); + if (errcode < 0) + return errcode; + + if (mcount < 0) + return -pte_internal; + + return 0; +} + +int pt_section_request_bcache(struct pt_section *section) +{ + struct pt_image_section_cache *iscache; + uint64_t memsize; + int errcode; + + if (!section) + return -pte_internal; + + errcode = pt_section_lock_attach(section); + if (errcode < 0) + return errcode; + + errcode = pt_section_lock(section); + if (errcode < 0) + goto out_alock; + + if (section->bcsize) + goto out_lock; + + section->bcsize = section->size * 3; + memsize = section->size + section->bcsize; + + errcode = pt_section_unlock(section); + if (errcode < 0) + goto out_alock; + + iscache = section->iscache; + if (iscache) { + errcode = pt_iscache_notify_resize(iscache, section, memsize); + if (errcode < 0) + goto out_alock; + } + + return pt_section_unlock_attach(section); + + +out_lock: + (void) pt_section_unlock(section); + +out_alock: + (void) pt_section_unlock_attach(section); + return errcode; +} + +const char *pt_section_filename(const struct pt_section *section) +{ + if (!section) + return NULL; + + return section->filename; +} + +uint64_t pt_section_offset(const struct pt_section *section) +{ + if (!section) + return 0ull; + + return section->offset; +} + +uint64_t pt_section_size(const struct pt_section *section) +{ + if (!section) + return 0ull; + + return section->size; +} + +int pt_section_memsize(struct pt_section *section, uint64_t *size) +{ + if (!section || !size) + return -pte_internal; + + *size = section->mcount ? section->size + section->bcsize : 0ull; + + return 0; +} + +int pt_section_read(const struct pt_section *section, uint8_t *buffer, + uint16_t size, uint64_t offset) +{ + uint64_t begin, end, max; + + if (!section || !buffer) + return -pte_internal; + + begin = offset; + end = begin + size; + max = sizeof(section->content); + + if (max <= begin) + return -pte_nomap; + + if (max < end) + end = max; + + if (end <= begin) + return -pte_invalid; + + memcpy(buffer, §ion->content[begin], (size_t) (end - begin)); + return (int) (end - begin); +} + +enum { + /* The number of test sections. */ + num_sections = 8, + +#if defined(FEATURE_THREADS) + + num_threads = 8, + +#endif /* defined(FEATURE_THREADS) */ + + num_iterations = 0x1000 +}; + +struct iscache_fixture { + /* Threading support. */ + struct ptunit_thrd_fixture thrd; + + /* The image section cache under test. */ + struct pt_image_section_cache iscache; + + /* A bunch of test sections. */ + struct pt_section *section[num_sections]; + + /* The test fixture initialization and finalization functions. */ + struct ptunit_result (*init)(struct iscache_fixture *); + struct ptunit_result (*fini)(struct iscache_fixture *); +}; + +static struct ptunit_result dfix_init(struct iscache_fixture *cfix) +{ + int idx; + + ptu_test(ptunit_thrd_init, &cfix->thrd); + + memset(cfix->section, 0, sizeof(cfix->section)); + + for (idx = 0; idx < num_sections; ++idx) { + struct pt_section *section; + int errcode; + + errcode = pt_mk_section(§ion, "some-filename", + idx % 3 == 0 ? 0x1000 : 0x2000, + idx % 2 == 0 ? 0x1000 : 0x2000); + ptu_int_eq(errcode, 0); + ptu_ptr(section); + + cfix->section[idx] = section; + } + + return ptu_passed(); +} + +static struct ptunit_result cfix_init(struct iscache_fixture *cfix) +{ + int errcode; + + ptu_test(dfix_init, cfix); + + errcode = pt_iscache_init(&cfix->iscache, NULL); + ptu_int_eq(errcode, 0); + + return ptu_passed(); +} + +static struct ptunit_result sfix_init(struct iscache_fixture *cfix) +{ + int status, idx; + + ptu_test(cfix_init, cfix); + + cfix->iscache.limit = 0x7800; + + for (idx = 0; idx < num_sections; ++idx) { + status = pt_iscache_add(&cfix->iscache, cfix->section[idx], + 0ull); + ptu_int_ge(status, 0); + } + + return ptu_passed(); +} + +static struct ptunit_result cfix_fini(struct iscache_fixture *cfix) +{ + int idx, errcode; + + ptu_test(ptunit_thrd_fini, &cfix->thrd); + + for (idx = 0; idx < cfix->thrd.nthreads; ++idx) + ptu_int_eq(cfix->thrd.result[idx], 0); + + pt_iscache_fini(&cfix->iscache); + + for (idx = 0; idx < num_sections; ++idx) { + ptu_int_eq(cfix->section[idx]->ucount, 1); + ptu_int_eq(cfix->section[idx]->acount, 0); + ptu_int_eq(cfix->section[idx]->mcount, 0); + ptu_null(cfix->section[idx]->iscache); + + errcode = pt_section_put(cfix->section[idx]); + ptu_int_eq(errcode, 0); + } + + return ptu_passed(); +} + + +static struct ptunit_result init_null(void) +{ + int errcode; + + errcode = pt_iscache_init(NULL, NULL); + ptu_int_eq(errcode, -pte_internal); + + return ptu_passed(); +} + +static struct ptunit_result fini_null(void) +{ + pt_iscache_fini(NULL); + + return ptu_passed(); +} + +static struct ptunit_result name_null(void) +{ + const char *name; + + name = pt_iscache_name(NULL); + ptu_null(name); + + return ptu_passed(); +} + +static struct ptunit_result add_null(void) +{ + struct pt_image_section_cache iscache; + struct pt_section section; + int errcode; + + errcode = pt_iscache_add(NULL, §ion, 0ull); + ptu_int_eq(errcode, -pte_internal); + + errcode = pt_iscache_add(&iscache, NULL, 0ull); + ptu_int_eq(errcode, -pte_internal); + + return ptu_passed(); +} + +static struct ptunit_result find_null(void) +{ + int errcode; + + errcode = pt_iscache_find(NULL, "filename", 0ull, 0ull, 0ull); + ptu_int_eq(errcode, -pte_internal); + + return ptu_passed(); +} + +static struct ptunit_result lookup_null(void) +{ + struct pt_image_section_cache iscache; + struct pt_section *section; + uint64_t laddr; + int errcode; + + errcode = pt_iscache_lookup(NULL, §ion, &laddr, 0); + ptu_int_eq(errcode, -pte_internal); + + errcode = pt_iscache_lookup(&iscache, NULL, &laddr, 0); + ptu_int_eq(errcode, -pte_internal); + + errcode = pt_iscache_lookup(&iscache, §ion, NULL, 0); + ptu_int_eq(errcode, -pte_internal); + + return ptu_passed(); +} + +static struct ptunit_result clear_null(void) +{ + int errcode; + + errcode = pt_iscache_clear(NULL); + ptu_int_eq(errcode, -pte_internal); + + return ptu_passed(); +} + +static struct ptunit_result free_null(void) +{ + pt_iscache_free(NULL); + + return ptu_passed(); +} + +static struct ptunit_result add_file_null(void) +{ + struct pt_image_section_cache iscache; + int errcode; + + errcode = pt_iscache_add_file(NULL, "filename", 0ull, 0ull, 0ull); + ptu_int_eq(errcode, -pte_invalid); + + errcode = pt_iscache_add_file(&iscache, NULL, 0ull, 0ull, 0ull); + ptu_int_eq(errcode, -pte_invalid); + + return ptu_passed(); +} + +static struct ptunit_result read_null(void) +{ + struct pt_image_section_cache iscache; + uint8_t buffer; + int errcode; + + errcode = pt_iscache_read(NULL, &buffer, sizeof(buffer), 1ull, 0ull); + ptu_int_eq(errcode, -pte_invalid); + + errcode = pt_iscache_read(&iscache, NULL, sizeof(buffer), 1ull, 0ull); + ptu_int_eq(errcode, -pte_invalid); + + errcode = pt_iscache_read(&iscache, &buffer, 0ull, 1, 0ull); + ptu_int_eq(errcode, -pte_invalid); + + return ptu_passed(); +} + +static struct ptunit_result init_fini(struct iscache_fixture *cfix) +{ + (void) cfix; + + /* The actual init and fini calls are in cfix_init() and cfix_fini(). */ + return ptu_passed(); +} + +static struct ptunit_result name(struct iscache_fixture *cfix) +{ + const char *name; + + pt_iscache_init(&cfix->iscache, "iscache-name"); + + name = pt_iscache_name(&cfix->iscache); + ptu_str_eq(name, "iscache-name"); + + return ptu_passed(); +} + +static struct ptunit_result name_none(struct iscache_fixture *cfix) +{ + const char *name; + + pt_iscache_init(&cfix->iscache, NULL); + + name = pt_iscache_name(&cfix->iscache); + ptu_null(name); + + return ptu_passed(); +} + +static struct ptunit_result add(struct iscache_fixture *cfix) +{ + int isid; + + isid = pt_iscache_add(&cfix->iscache, cfix->section[0], 0ull); + ptu_int_gt(isid, 0); + + /* The cache attaches and gets a reference on success. */ + ptu_int_eq(cfix->section[0]->ucount, 2); + ptu_int_eq(cfix->section[0]->acount, 1); + + /* The added section must be implicitly put in pt_iscache_fini. */ + return ptu_passed(); +} + +static struct ptunit_result add_no_name(struct iscache_fixture *cfix) +{ + struct pt_section section; + int errcode; + + memset(§ion, 0, sizeof(section)); + + errcode = pt_iscache_add(&cfix->iscache, §ion, 0ull); + ptu_int_eq(errcode, -pte_internal); + + return ptu_passed(); +} + +static struct ptunit_result add_file(struct iscache_fixture *cfix) +{ + int isid; + + isid = pt_iscache_add_file(&cfix->iscache, "name", 0ull, 1ull, 0ull); + ptu_int_gt(isid, 0); + + return ptu_passed(); +} + +static struct ptunit_result find(struct iscache_fixture *cfix) +{ + struct pt_section *section; + int found, isid; + + section = cfix->section[0]; + ptu_ptr(section); + + isid = pt_iscache_add(&cfix->iscache, section, 0ull); + ptu_int_gt(isid, 0); + + found = pt_iscache_find(&cfix->iscache, section->filename, + section->offset, section->size, 0ull); + ptu_int_eq(found, isid); + + return ptu_passed(); +} + +static struct ptunit_result find_empty(struct iscache_fixture *cfix) +{ + struct pt_section *section; + int found; + + section = cfix->section[0]; + ptu_ptr(section); + + found = pt_iscache_find(&cfix->iscache, section->filename, + section->offset, section->size, 0ull); + ptu_int_eq(found, 0); + + return ptu_passed(); +} + +static struct ptunit_result find_bad_filename(struct iscache_fixture *cfix) +{ + struct pt_section *section; + int found, isid; + + section = cfix->section[0]; + ptu_ptr(section); + + isid = pt_iscache_add(&cfix->iscache, section, 0ull); + ptu_int_gt(isid, 0); + + found = pt_iscache_find(&cfix->iscache, "bad-filename", + section->offset, section->size, 0ull); + ptu_int_eq(found, 0); + + return ptu_passed(); +} + +static struct ptunit_result find_null_filename(struct iscache_fixture *cfix) +{ + int errcode; + + errcode = pt_iscache_find(&cfix->iscache, NULL, 0ull, 0ull, 0ull); + ptu_int_eq(errcode, -pte_internal); + + return ptu_passed(); +} + +static struct ptunit_result find_bad_offset(struct iscache_fixture *cfix) +{ + struct pt_section *section; + int found, isid; + + section = cfix->section[0]; + ptu_ptr(section); + + isid = pt_iscache_add(&cfix->iscache, section, 0ull); + ptu_int_gt(isid, 0); + + found = pt_iscache_find(&cfix->iscache, section->filename, 0ull, + section->size, 0ull); + ptu_int_eq(found, 0); + + return ptu_passed(); +} + +static struct ptunit_result find_bad_size(struct iscache_fixture *cfix) +{ + struct pt_section *section; + int found, isid; + + section = cfix->section[0]; + ptu_ptr(section); + + isid = pt_iscache_add(&cfix->iscache, section, 0ull); + ptu_int_gt(isid, 0); + + found = pt_iscache_find(&cfix->iscache, section->filename, + section->offset, 0ull, 0ull); + ptu_int_eq(found, 0); + + return ptu_passed(); +} + +static struct ptunit_result find_bad_laddr(struct iscache_fixture *cfix) +{ + struct pt_section *section; + int found, isid; + + section = cfix->section[0]; + ptu_ptr(section); + + isid = pt_iscache_add(&cfix->iscache, section, 0ull); + ptu_int_gt(isid, 0); + + found = pt_iscache_find(&cfix->iscache, section->filename, + section->offset, section->size, 1ull); + ptu_int_eq(found, 0); + + return ptu_passed(); +} + +static struct ptunit_result lookup(struct iscache_fixture *cfix) +{ + struct pt_section *section; + uint64_t laddr; + int errcode, isid; + + isid = pt_iscache_add(&cfix->iscache, cfix->section[0], 0ull); + ptu_int_gt(isid, 0); + + errcode = pt_iscache_lookup(&cfix->iscache, §ion, &laddr, isid); + ptu_int_eq(errcode, 0); + ptu_ptr_eq(section, cfix->section[0]); + ptu_uint_eq(laddr, 0ull); + + errcode = pt_section_put(section); + ptu_int_eq(errcode, 0); + + return ptu_passed(); +} + +static struct ptunit_result lookup_bad_isid(struct iscache_fixture *cfix) +{ + struct pt_section *section; + uint64_t laddr; + int errcode, isid; + + isid = pt_iscache_add(&cfix->iscache, cfix->section[0], 0ull); + ptu_int_gt(isid, 0); + + errcode = pt_iscache_lookup(&cfix->iscache, §ion, &laddr, 0); + ptu_int_eq(errcode, -pte_bad_image); + + errcode = pt_iscache_lookup(&cfix->iscache, §ion, &laddr, -isid); + ptu_int_eq(errcode, -pte_bad_image); + + errcode = pt_iscache_lookup(&cfix->iscache, §ion, &laddr, isid + 1); + ptu_int_eq(errcode, -pte_bad_image); + + return ptu_passed(); +} + +static struct ptunit_result clear_empty(struct iscache_fixture *cfix) +{ + int errcode; + + errcode = pt_iscache_clear(&cfix->iscache); + ptu_int_eq(errcode, 0); + + return ptu_passed(); +} + +static struct ptunit_result clear_find(struct iscache_fixture *cfix) +{ + struct pt_section *section; + int errcode, found, isid; + + section = cfix->section[0]; + ptu_ptr(section); + + isid = pt_iscache_add(&cfix->iscache, section, 0ull); + ptu_int_gt(isid, 0); + + errcode = pt_iscache_clear(&cfix->iscache); + ptu_int_eq(errcode, 0); + + + found = pt_iscache_find(&cfix->iscache, section->filename, + section->offset, section->size, 0ull); + ptu_int_eq(found, 0); + + return ptu_passed(); +} + +static struct ptunit_result clear_lookup(struct iscache_fixture *cfix) +{ + struct pt_section *section; + uint64_t laddr; + int errcode, isid; + + isid = pt_iscache_add(&cfix->iscache, cfix->section[0], 0ull); + ptu_int_gt(isid, 0); + + errcode = pt_iscache_clear(&cfix->iscache); + ptu_int_eq(errcode, 0); + + errcode = pt_iscache_lookup(&cfix->iscache, §ion, &laddr, isid); + ptu_int_eq(errcode, -pte_bad_image); + + return ptu_passed(); +} + +static struct ptunit_result add_twice(struct iscache_fixture *cfix) +{ + int isid[2]; + + isid[0] = pt_iscache_add(&cfix->iscache, cfix->section[0], 0ull); + ptu_int_gt(isid[0], 0); + + isid[1] = pt_iscache_add(&cfix->iscache, cfix->section[0], 0ull); + ptu_int_gt(isid[1], 0); + + /* The second add should be ignored. */ + ptu_int_eq(isid[1], isid[0]); + + return ptu_passed(); +} + +static struct ptunit_result add_same(struct iscache_fixture *cfix) +{ + int isid[2]; + + isid[0] = pt_iscache_add(&cfix->iscache, cfix->section[0], 0ull); + ptu_int_gt(isid[0], 0); + + cfix->section[1]->offset = cfix->section[0]->offset; + cfix->section[1]->size = cfix->section[0]->size; + + isid[1] = pt_iscache_add(&cfix->iscache, cfix->section[1], 0ull); + ptu_int_gt(isid[1], 0); + + /* The second add should be ignored. */ + ptu_int_eq(isid[1], isid[0]); + + return ptu_passed(); +} + +static struct ptunit_result +add_twice_different_laddr(struct iscache_fixture *cfix) +{ + int isid[2]; + + isid[0] = pt_iscache_add(&cfix->iscache, cfix->section[0], 0ull); + ptu_int_gt(isid[0], 0); + + isid[1] = pt_iscache_add(&cfix->iscache, cfix->section[0], 1ull); + ptu_int_gt(isid[1], 0); + + /* We must get different identifiers. */ + ptu_int_ne(isid[1], isid[0]); + + /* We attach twice and take two references - one for each entry. */ + ptu_int_eq(cfix->section[0]->ucount, 3); + ptu_int_eq(cfix->section[0]->acount, 2); + + return ptu_passed(); +} + +static struct ptunit_result +add_same_different_laddr(struct iscache_fixture *cfix) +{ + int isid[2]; + + isid[0] = pt_iscache_add(&cfix->iscache, cfix->section[0], 0ull); + ptu_int_gt(isid[0], 0); + + cfix->section[1]->offset = cfix->section[0]->offset; + cfix->section[1]->size = cfix->section[0]->size; + + isid[1] = pt_iscache_add(&cfix->iscache, cfix->section[1], 1ull); + ptu_int_gt(isid[1], 0); + + /* We must get different identifiers. */ + ptu_int_ne(isid[1], isid[0]); + + return ptu_passed(); +} + +static struct ptunit_result +add_different_same_laddr(struct iscache_fixture *cfix) +{ + int isid[2]; + + isid[0] = pt_iscache_add(&cfix->iscache, cfix->section[0], 0ull); + ptu_int_gt(isid[0], 0); + + isid[1] = pt_iscache_add(&cfix->iscache, cfix->section[1], 0ull); + ptu_int_gt(isid[1], 0); + + /* We must get different identifiers. */ + ptu_int_ne(isid[1], isid[0]); + + return ptu_passed(); +} + +static struct ptunit_result add_file_same(struct iscache_fixture *cfix) +{ + int isid[2]; + + isid[0] = pt_iscache_add_file(&cfix->iscache, "name", 0ull, 1ull, 0ull); + ptu_int_gt(isid[0], 0); + + isid[1] = pt_iscache_add_file(&cfix->iscache, "name", 0ull, 1ull, 0ull); + ptu_int_gt(isid[1], 0); + + /* The second add should be ignored. */ + ptu_int_eq(isid[1], isid[0]); + + return ptu_passed(); +} + +static struct ptunit_result +add_file_same_different_laddr(struct iscache_fixture *cfix) +{ + int isid[2]; + + isid[0] = pt_iscache_add_file(&cfix->iscache, "name", 0ull, 1ull, 0ull); + ptu_int_gt(isid[0], 0); + + isid[1] = pt_iscache_add_file(&cfix->iscache, "name", 0ull, 1ull, 1ull); + ptu_int_gt(isid[1], 0); + + /* We must get different identifiers. */ + ptu_int_ne(isid[1], isid[0]); + + return ptu_passed(); +} + +static struct ptunit_result +add_file_different_same_laddr(struct iscache_fixture *cfix) +{ + int isid[2]; + + isid[0] = pt_iscache_add_file(&cfix->iscache, "name", 0ull, 1ull, 0ull); + ptu_int_gt(isid[0], 0); + + isid[1] = pt_iscache_add_file(&cfix->iscache, "name", 1ull, 1ull, 0ull); + ptu_int_gt(isid[1], 0); + + /* We must get different identifiers. */ + ptu_int_ne(isid[1], isid[0]); + + return ptu_passed(); +} + +static struct ptunit_result read(struct iscache_fixture *cfix) +{ + uint8_t buffer[] = { 0xcc, 0xcc, 0xcc }; + int status, isid; + + isid = pt_iscache_add(&cfix->iscache, cfix->section[0], 0xa000ull); + ptu_int_gt(isid, 0); + + status = pt_iscache_read(&cfix->iscache, buffer, 2ull, isid, 0xa008ull); + ptu_int_eq(status, 2); + ptu_uint_eq(buffer[0], 0x8); + ptu_uint_eq(buffer[1], 0x9); + ptu_uint_eq(buffer[2], 0xcc); + + return ptu_passed(); +} + +static struct ptunit_result read_truncate(struct iscache_fixture *cfix) +{ + uint8_t buffer[] = { 0xcc, 0xcc }; + int status, isid; + + isid = pt_iscache_add(&cfix->iscache, cfix->section[0], 0xa000ull); + ptu_int_gt(isid, 0); + + status = pt_iscache_read(&cfix->iscache, buffer, sizeof(buffer), isid, + 0xa00full); + ptu_int_eq(status, 1); + ptu_uint_eq(buffer[0], 0xf); + ptu_uint_eq(buffer[1], 0xcc); + + return ptu_passed(); +} + +static struct ptunit_result read_bad_vaddr(struct iscache_fixture *cfix) +{ + uint8_t buffer[] = { 0xcc }; + int status, isid; + + isid = pt_iscache_add(&cfix->iscache, cfix->section[0], 0xa000ull); + ptu_int_gt(isid, 0); + + status = pt_iscache_read(&cfix->iscache, buffer, 1ull, isid, 0xb000ull); + ptu_int_eq(status, -pte_nomap); + ptu_uint_eq(buffer[0], 0xcc); + + return ptu_passed(); +} + +static struct ptunit_result read_bad_isid(struct iscache_fixture *cfix) +{ + uint8_t buffer[] = { 0xcc }; + int status, isid; + + isid = pt_iscache_add(&cfix->iscache, cfix->section[0], 0xa000ull); + ptu_int_gt(isid, 0); + + status = pt_iscache_read(&cfix->iscache, buffer, 1ull, isid + 1, + 0xa000ull); + ptu_int_eq(status, -pte_bad_image); + ptu_uint_eq(buffer[0], 0xcc); + + return ptu_passed(); +} + +static struct ptunit_result lru_map(struct iscache_fixture *cfix) +{ + int status, isid; + + cfix->iscache.limit = cfix->section[0]->size; + ptu_uint_eq(cfix->iscache.used, 0ull); + ptu_null(cfix->iscache.lru); + + isid = pt_iscache_add(&cfix->iscache, cfix->section[0], 0xa000ull); + ptu_int_gt(isid, 0); + + status = pt_section_map(cfix->section[0]); + ptu_int_eq(status, 0); + + status = pt_section_unmap(cfix->section[0]); + ptu_int_eq(status, 0); + + ptu_ptr(cfix->iscache.lru); + ptu_ptr_eq(cfix->iscache.lru->section, cfix->section[0]); + ptu_null(cfix->iscache.lru->next); + ptu_uint_eq(cfix->iscache.used, cfix->section[0]->size); + + return ptu_passed(); +} + +static struct ptunit_result lru_read(struct iscache_fixture *cfix) +{ + uint8_t buffer[] = { 0xcc, 0xcc, 0xcc }; + int status, isid; + + cfix->iscache.limit = cfix->section[0]->size; + ptu_uint_eq(cfix->iscache.used, 0ull); + ptu_null(cfix->iscache.lru); + + isid = pt_iscache_add(&cfix->iscache, cfix->section[0], 0xa000ull); + ptu_int_gt(isid, 0); + + status = pt_iscache_read(&cfix->iscache, buffer, 2ull, isid, 0xa008ull); + ptu_int_eq(status, 2); + + ptu_ptr(cfix->iscache.lru); + ptu_ptr_eq(cfix->iscache.lru->section, cfix->section[0]); + ptu_null(cfix->iscache.lru->next); + ptu_uint_eq(cfix->iscache.used, cfix->section[0]->size); + + return ptu_passed(); +} + +static struct ptunit_result lru_map_nodup(struct iscache_fixture *cfix) +{ + int status, isid; + + cfix->iscache.limit = 2 * cfix->section[0]->size; + ptu_uint_eq(cfix->iscache.used, 0ull); + ptu_null(cfix->iscache.lru); + + isid = pt_iscache_add(&cfix->iscache, cfix->section[0], 0xa000ull); + ptu_int_gt(isid, 0); + + status = pt_section_map(cfix->section[0]); + ptu_int_eq(status, 0); + + status = pt_section_unmap(cfix->section[0]); + ptu_int_eq(status, 0); + + status = pt_section_map(cfix->section[0]); + ptu_int_eq(status, 0); + + status = pt_section_unmap(cfix->section[0]); + ptu_int_eq(status, 0); + + ptu_ptr(cfix->iscache.lru); + ptu_ptr_eq(cfix->iscache.lru->section, cfix->section[0]); + ptu_null(cfix->iscache.lru->next); + ptu_uint_eq(cfix->iscache.used, cfix->section[0]->size); + + return ptu_passed(); +} + +static struct ptunit_result lru_map_too_big(struct iscache_fixture *cfix) +{ + int status, isid; + + cfix->iscache.limit = cfix->section[0]->size - 1; + ptu_uint_eq(cfix->iscache.used, 0ull); + ptu_null(cfix->iscache.lru); + + isid = pt_iscache_add(&cfix->iscache, cfix->section[0], 0xa000ull); + ptu_int_gt(isid, 0); + + status = pt_section_map(cfix->section[0]); + ptu_int_eq(status, 0); + + status = pt_section_unmap(cfix->section[0]); + ptu_int_eq(status, 0); + + ptu_null(cfix->iscache.lru); + ptu_uint_eq(cfix->iscache.used, 0ull); + + return ptu_passed(); +} + +static struct ptunit_result lru_map_add_front(struct iscache_fixture *cfix) +{ + int status, isid; + + cfix->iscache.limit = cfix->section[0]->size + cfix->section[1]->size; + ptu_uint_eq(cfix->iscache.used, 0ull); + ptu_null(cfix->iscache.lru); + + isid = pt_iscache_add(&cfix->iscache, cfix->section[0], 0xa000ull); + ptu_int_gt(isid, 0); + + isid = pt_iscache_add(&cfix->iscache, cfix->section[1], 0xa000ull); + ptu_int_gt(isid, 0); + + status = pt_section_map(cfix->section[0]); + ptu_int_eq(status, 0); + + status = pt_section_unmap(cfix->section[0]); + ptu_int_eq(status, 0); + + status = pt_section_map(cfix->section[1]); + ptu_int_eq(status, 0); + + status = pt_section_unmap(cfix->section[1]); + ptu_int_eq(status, 0); + + ptu_ptr(cfix->iscache.lru); + ptu_ptr_eq(cfix->iscache.lru->section, cfix->section[1]); + ptu_ptr(cfix->iscache.lru->next); + ptu_ptr_eq(cfix->iscache.lru->next->section, cfix->section[0]); + ptu_null(cfix->iscache.lru->next->next); + ptu_uint_eq(cfix->iscache.used, + cfix->section[0]->size + cfix->section[1]->size); + + return ptu_passed(); +} + +static struct ptunit_result lru_map_move_front(struct iscache_fixture *cfix) +{ + int status, isid; + + cfix->iscache.limit = cfix->section[0]->size + cfix->section[1]->size; + ptu_uint_eq(cfix->iscache.used, 0ull); + ptu_null(cfix->iscache.lru); + + isid = pt_iscache_add(&cfix->iscache, cfix->section[0], 0xa000ull); + ptu_int_gt(isid, 0); + + isid = pt_iscache_add(&cfix->iscache, cfix->section[1], 0xa000ull); + ptu_int_gt(isid, 0); + + status = pt_section_map(cfix->section[0]); + ptu_int_eq(status, 0); + + status = pt_section_unmap(cfix->section[0]); + ptu_int_eq(status, 0); + + status = pt_section_map(cfix->section[1]); + ptu_int_eq(status, 0); + + status = pt_section_unmap(cfix->section[1]); + ptu_int_eq(status, 0); + + status = pt_section_map(cfix->section[0]); + ptu_int_eq(status, 0); + + status = pt_section_unmap(cfix->section[0]); + ptu_int_eq(status, 0); + + ptu_ptr(cfix->iscache.lru); + ptu_ptr_eq(cfix->iscache.lru->section, cfix->section[0]); + ptu_ptr(cfix->iscache.lru->next); + ptu_ptr_eq(cfix->iscache.lru->next->section, cfix->section[1]); + ptu_null(cfix->iscache.lru->next->next); + ptu_uint_eq(cfix->iscache.used, + cfix->section[0]->size + cfix->section[1]->size); + + return ptu_passed(); +} + +static struct ptunit_result lru_map_evict(struct iscache_fixture *cfix) +{ + int status, isid; + + cfix->iscache.limit = cfix->section[0]->size + + cfix->section[1]->size - 1; + ptu_uint_eq(cfix->iscache.used, 0ull); + ptu_null(cfix->iscache.lru); + + isid = pt_iscache_add(&cfix->iscache, cfix->section[0], 0xa000ull); + ptu_int_gt(isid, 0); + + isid = pt_iscache_add(&cfix->iscache, cfix->section[1], 0xa000ull); + ptu_int_gt(isid, 0); + + status = pt_section_map(cfix->section[0]); + ptu_int_eq(status, 0); + + status = pt_section_unmap(cfix->section[0]); + ptu_int_eq(status, 0); + + status = pt_section_map(cfix->section[1]); + ptu_int_eq(status, 0); + + status = pt_section_unmap(cfix->section[1]); + ptu_int_eq(status, 0); + + ptu_ptr(cfix->iscache.lru); + ptu_ptr_eq(cfix->iscache.lru->section, cfix->section[1]); + ptu_null(cfix->iscache.lru->next); + ptu_uint_eq(cfix->iscache.used, cfix->section[1]->size); + + return ptu_passed(); +} + +static struct ptunit_result lru_bcache_evict(struct iscache_fixture *cfix) +{ + int status, isid; + + cfix->iscache.limit = 4 * cfix->section[0]->size + + cfix->section[1]->size - 1; + ptu_uint_eq(cfix->iscache.used, 0ull); + ptu_null(cfix->iscache.lru); + + isid = pt_iscache_add(&cfix->iscache, cfix->section[0], 0xa000ull); + ptu_int_gt(isid, 0); + + isid = pt_iscache_add(&cfix->iscache, cfix->section[1], 0xa000ull); + ptu_int_gt(isid, 0); + + status = pt_section_map(cfix->section[0]); + ptu_int_eq(status, 0); + + status = pt_section_unmap(cfix->section[0]); + ptu_int_eq(status, 0); + + status = pt_section_map(cfix->section[1]); + ptu_int_eq(status, 0); + + status = pt_section_unmap(cfix->section[1]); + ptu_int_eq(status, 0); + + status = pt_section_request_bcache(cfix->section[0]); + ptu_int_eq(status, 0); + + ptu_ptr(cfix->iscache.lru); + ptu_ptr_eq(cfix->iscache.lru->section, cfix->section[0]); + ptu_null(cfix->iscache.lru->next); + ptu_uint_eq(cfix->iscache.used, 4 * cfix->section[0]->size); + + return ptu_passed(); +} + +static struct ptunit_result lru_bcache_clear(struct iscache_fixture *cfix) +{ + int status, isid; + + cfix->iscache.limit = cfix->section[0]->size + cfix->section[1]->size; + ptu_uint_eq(cfix->iscache.used, 0ull); + ptu_null(cfix->iscache.lru); + + isid = pt_iscache_add(&cfix->iscache, cfix->section[0], 0xa000ull); + ptu_int_gt(isid, 0); + + isid = pt_iscache_add(&cfix->iscache, cfix->section[1], 0xa000ull); + ptu_int_gt(isid, 0); + + status = pt_section_map(cfix->section[0]); + ptu_int_eq(status, 0); + + status = pt_section_unmap(cfix->section[0]); + ptu_int_eq(status, 0); + + status = pt_section_map(cfix->section[1]); + ptu_int_eq(status, 0); + + status = pt_section_unmap(cfix->section[1]); + ptu_int_eq(status, 0); + + status = pt_section_request_bcache(cfix->section[0]); + ptu_int_eq(status, 0); + + ptu_null(cfix->iscache.lru); + ptu_uint_eq(cfix->iscache.used, 0ull); + + return ptu_passed(); +} + +static struct ptunit_result lru_limit_evict(struct iscache_fixture *cfix) +{ + int status, isid; + + cfix->iscache.limit = cfix->section[0]->size + cfix->section[1]->size; + ptu_uint_eq(cfix->iscache.used, 0ull); + ptu_null(cfix->iscache.lru); + + isid = pt_iscache_add(&cfix->iscache, cfix->section[0], 0xa000ull); + ptu_int_gt(isid, 0); + + isid = pt_iscache_add(&cfix->iscache, cfix->section[1], 0xa000ull); + ptu_int_gt(isid, 0); + + status = pt_section_map(cfix->section[0]); + ptu_int_eq(status, 0); + + status = pt_section_unmap(cfix->section[0]); + ptu_int_eq(status, 0); + + status = pt_section_map(cfix->section[1]); + ptu_int_eq(status, 0); + + status = pt_section_unmap(cfix->section[1]); + ptu_int_eq(status, 0); + + status = pt_iscache_set_limit(&cfix->iscache, + cfix->section[0]->size + + cfix->section[1]->size - 1); + ptu_int_eq(status, 0); + + ptu_ptr(cfix->iscache.lru); + ptu_ptr_eq(cfix->iscache.lru->section, cfix->section[1]); + ptu_null(cfix->iscache.lru->next); + ptu_uint_eq(cfix->iscache.used, cfix->section[1]->size); + + return ptu_passed(); +} + +static struct ptunit_result lru_clear(struct iscache_fixture *cfix) +{ + int status, isid; + + cfix->iscache.limit = cfix->section[0]->size; + ptu_uint_eq(cfix->iscache.used, 0ull); + ptu_null(cfix->iscache.lru); + + isid = pt_iscache_add(&cfix->iscache, cfix->section[0], 0xa000ull); + ptu_int_gt(isid, 0); + + status = pt_section_map(cfix->section[0]); + ptu_int_eq(status, 0); + + status = pt_section_unmap(cfix->section[0]); + ptu_int_eq(status, 0); + + status = pt_iscache_clear(&cfix->iscache); + ptu_int_eq(status, 0); + + ptu_null(cfix->iscache.lru); + ptu_uint_eq(cfix->iscache.used, 0ull); + + return ptu_passed(); +} + +static int worker_add(void *arg) +{ + struct iscache_fixture *cfix; + int it; + + cfix = arg; + if (!cfix) + return -pte_internal; + + for (it = 0; it < num_iterations; ++it) { + uint64_t laddr; + int sec; + + laddr = 0x1000ull * (it % 23); + + for (sec = 0; sec < num_sections; ++sec) { + struct pt_section *section; + uint64_t addr; + int isid, errcode; + + isid = pt_iscache_add(&cfix->iscache, + cfix->section[sec], laddr); + if (isid < 0) + return isid; + + errcode = pt_iscache_lookup(&cfix->iscache, §ion, + &addr, isid); + if (errcode < 0) + return errcode; + + if (laddr != addr) + return -pte_noip; + + /* We may not get the image we added but the image we + * get must have similar attributes. + * + * We're using the same filename string literal for all + * sections, though. + */ + if (section->offset != cfix->section[sec]->offset) + return -pte_bad_image; + + if (section->size != cfix->section[sec]->size) + return -pte_bad_image; + + errcode = pt_section_put(section); + if (errcode < 0) + return errcode; + } + } + + return 0; +} + +static int worker_add_file(void *arg) +{ + struct iscache_fixture *cfix; + int it; + + cfix = arg; + if (!cfix) + return -pte_internal; + + for (it = 0; it < num_iterations; ++it) { + uint64_t offset, size, laddr; + int sec; + + offset = it % 7 == 0 ? 0x1000 : 0x2000; + size = it % 5 == 0 ? 0x1000 : 0x2000; + laddr = it % 3 == 0 ? 0x1000 : 0x2000; + + for (sec = 0; sec < num_sections; ++sec) { + struct pt_section *section; + uint64_t addr; + int isid, errcode; + + isid = pt_iscache_add_file(&cfix->iscache, "name", + offset, size, laddr); + if (isid < 0) + return isid; + + errcode = pt_iscache_lookup(&cfix->iscache, §ion, + &addr, isid); + if (errcode < 0) + return errcode; + + if (laddr != addr) + return -pte_noip; + + if (section->offset != offset) + return -pte_bad_image; + + if (section->size != size) + return -pte_bad_image; + + errcode = pt_section_put(section); + if (errcode < 0) + return errcode; + } + } + + return 0; +} + +static int worker_map(void *arg) +{ + struct iscache_fixture *cfix; + int it, sec, status; + + cfix = arg; + if (!cfix) + return -pte_internal; + + for (it = 0; it < num_iterations; ++it) { + for (sec = 0; sec < num_sections; ++sec) { + + status = pt_section_map(cfix->section[sec]); + if (status < 0) + return status; + + status = pt_section_unmap(cfix->section[sec]); + if (status < 0) + return status; + } + } + + return 0; +} + +static int worker_map_limit(void *arg) +{ + struct iscache_fixture *cfix; + uint64_t limits[] = { 0x8000, 0x3000, 0x12000, 0x0 }, limit; + int it, sec, errcode, lim; + + cfix = arg; + if (!cfix) + return -pte_internal; + + lim = 0; + for (it = 0; it < num_iterations; ++it) { + for (sec = 0; sec < num_sections; ++sec) { + + errcode = pt_section_map(cfix->section[sec]); + if (errcode < 0) + return errcode; + + errcode = pt_section_unmap(cfix->section[sec]); + if (errcode < 0) + return errcode; + } + + if (it % 23 != 0) + continue; + + limit = limits[lim++]; + lim %= sizeof(limits) / sizeof(*limits); + + errcode = pt_iscache_set_limit(&cfix->iscache, limit); + if (errcode < 0) + return errcode; + } + + return 0; +} + +static int worker_map_bcache(void *arg) +{ + struct iscache_fixture *cfix; + int it, sec, status; + + cfix = arg; + if (!cfix) + return -pte_internal; + + for (it = 0; it < num_iterations; ++it) { + for (sec = 0; sec < num_sections; ++sec) { + struct pt_section *section; + + section = cfix->section[sec]; + + status = pt_section_map(section); + if (status < 0) + return status; + + if (it % 13 == 0) { + status = pt_section_request_bcache(section); + if (status < 0) { + (void) pt_section_unmap(section); + return status; + } + } + + status = pt_section_unmap(section); + if (status < 0) + return status; + } + } + + return 0; +} + +static int worker_add_map(void *arg) +{ + struct iscache_fixture *cfix; + struct pt_section *section; + int it; + + cfix = arg; + if (!cfix) + return -pte_internal; + + section = cfix->section[0]; + for (it = 0; it < num_iterations; ++it) { + uint64_t laddr; + int isid, errcode; + + laddr = (uint64_t) it << 3; + + isid = pt_iscache_add(&cfix->iscache, section, laddr); + if (isid < 0) + return isid; + + errcode = pt_section_map(section); + if (errcode < 0) + return errcode; + + errcode = pt_section_unmap(section); + if (errcode < 0) + return errcode; + } + + return 0; +} + +static int worker_add_clear(void *arg) +{ + struct iscache_fixture *cfix; + struct pt_section *section; + int it; + + cfix = arg; + if (!cfix) + return -pte_internal; + + section = cfix->section[0]; + for (it = 0; it < num_iterations; ++it) { + uint64_t laddr; + int isid, errcode; + + laddr = (uint64_t) it << 3; + + isid = pt_iscache_add(&cfix->iscache, section, laddr); + if (isid < 0) + return isid; + + errcode = pt_iscache_clear(&cfix->iscache); + if (errcode < 0) + return errcode; + } + + return 0; +} + +static int worker_add_file_map(void *arg) +{ + struct iscache_fixture *cfix; + int it; + + cfix = arg; + if (!cfix) + return -pte_internal; + + for (it = 0; it < num_iterations; ++it) { + struct pt_section *section; + uint64_t offset, size, laddr, addr; + int isid, errcode; + + offset = it % 7 < 4 ? 0x1000 : 0x2000; + size = it % 5 < 3 ? 0x1000 : 0x2000; + laddr = it % 3 < 2 ? 0x1000 : 0x2000; + + isid = pt_iscache_add_file(&cfix->iscache, "name", + offset, size, laddr); + if (isid < 0) + return isid; + + errcode = pt_iscache_lookup(&cfix->iscache, §ion, + &addr, isid); + if (errcode < 0) + return errcode; + + if (addr != laddr) + return -pte_internal; + + errcode = pt_section_map(section); + if (errcode < 0) + return errcode; + + errcode = pt_section_unmap(section); + if (errcode < 0) + return errcode; + } + + return 0; +} + +static int worker_add_file_clear(void *arg) +{ + struct iscache_fixture *cfix; + int it; + + cfix = arg; + if (!cfix) + return -pte_internal; + + for (it = 0; it < num_iterations; ++it) { + uint64_t offset, size, laddr; + int isid, errcode; + + offset = it % 7 < 4 ? 0x1000 : 0x2000; + size = it % 5 < 3 ? 0x1000 : 0x2000; + laddr = it % 3 < 2 ? 0x1000 : 0x2000; + + isid = pt_iscache_add_file(&cfix->iscache, "name", + offset, size, laddr); + if (isid < 0) + return isid; + + if (it % 11 < 9) + continue; + + errcode = pt_iscache_clear(&cfix->iscache); + if (errcode < 0) + return errcode; + } + + return 0; +} + +static struct ptunit_result stress(struct iscache_fixture *cfix, + int (*worker)(void *)) +{ + int errcode; + +#if defined(FEATURE_THREADS) + { + int thrd; + + for (thrd = 0; thrd < num_threads; ++thrd) + ptu_test(ptunit_thrd_create, &cfix->thrd, worker, cfix); + } +#endif /* defined(FEATURE_THREADS) */ + + errcode = worker(cfix); + ptu_int_eq(errcode, 0); + + return ptu_passed(); +} +int main(int argc, char **argv) +{ + struct iscache_fixture cfix, dfix, sfix; + struct ptunit_suite suite; + + cfix.init = cfix_init; + cfix.fini = cfix_fini; + + dfix.init = dfix_init; + dfix.fini = cfix_fini; + + sfix.init = sfix_init; + sfix.fini = cfix_fini; + + suite = ptunit_mk_suite(argc, argv); + + ptu_run(suite, init_null); + ptu_run(suite, fini_null); + ptu_run(suite, name_null); + ptu_run(suite, add_null); + ptu_run(suite, find_null); + ptu_run(suite, lookup_null); + ptu_run(suite, clear_null); + ptu_run(suite, free_null); + ptu_run(suite, add_file_null); + ptu_run(suite, read_null); + + ptu_run_f(suite, name, dfix); + ptu_run_f(suite, name_none, dfix); + + ptu_run_f(suite, init_fini, cfix); + ptu_run_f(suite, add, cfix); + ptu_run_f(suite, add_no_name, cfix); + ptu_run_f(suite, add_file, cfix); + + ptu_run_f(suite, find, cfix); + ptu_run_f(suite, find_empty, cfix); + ptu_run_f(suite, find_bad_filename, cfix); + ptu_run_f(suite, find_null_filename, cfix); + ptu_run_f(suite, find_bad_offset, cfix); + ptu_run_f(suite, find_bad_size, cfix); + ptu_run_f(suite, find_bad_laddr, cfix); + + ptu_run_f(suite, lookup, cfix); + ptu_run_f(suite, lookup_bad_isid, cfix); + + ptu_run_f(suite, clear_empty, cfix); + ptu_run_f(suite, clear_find, cfix); + ptu_run_f(suite, clear_lookup, cfix); + + ptu_run_f(suite, add_twice, cfix); + ptu_run_f(suite, add_same, cfix); + ptu_run_f(suite, add_twice_different_laddr, cfix); + ptu_run_f(suite, add_same_different_laddr, cfix); + ptu_run_f(suite, add_different_same_laddr, cfix); + + ptu_run_f(suite, add_file_same, cfix); + ptu_run_f(suite, add_file_same_different_laddr, cfix); + ptu_run_f(suite, add_file_different_same_laddr, cfix); + + ptu_run_f(suite, read, cfix); + ptu_run_f(suite, read_truncate, cfix); + ptu_run_f(suite, read_bad_vaddr, cfix); + ptu_run_f(suite, read_bad_isid, cfix); + + ptu_run_f(suite, lru_map, cfix); + ptu_run_f(suite, lru_read, cfix); + ptu_run_f(suite, lru_map_nodup, cfix); + ptu_run_f(suite, lru_map_too_big, cfix); + ptu_run_f(suite, lru_map_add_front, cfix); + ptu_run_f(suite, lru_map_move_front, cfix); + ptu_run_f(suite, lru_map_evict, cfix); + ptu_run_f(suite, lru_limit_evict, cfix); + ptu_run_f(suite, lru_bcache_evict, cfix); + ptu_run_f(suite, lru_bcache_clear, cfix); + ptu_run_f(suite, lru_clear, cfix); + + ptu_run_fp(suite, stress, cfix, worker_add); + ptu_run_fp(suite, stress, cfix, worker_add_file); + ptu_run_fp(suite, stress, sfix, worker_map); + ptu_run_fp(suite, stress, sfix, worker_map_limit); + ptu_run_fp(suite, stress, sfix, worker_map_bcache); + ptu_run_fp(suite, stress, cfix, worker_add_map); + ptu_run_fp(suite, stress, cfix, worker_add_clear); + ptu_run_fp(suite, stress, cfix, worker_add_file_map); + ptu_run_fp(suite, stress, cfix, worker_add_file_clear); + + return ptunit_report(&suite); +} diff --git a/libipt/test/src/ptunit-insn_decoder.c b/libipt/test/src/ptunit-insn_decoder.c new file mode 100644 index 0000000000000..a45bafa36669c --- /dev/null +++ b/libipt/test/src/ptunit-insn_decoder.c @@ -0,0 +1,351 @@ +/* + * Copyright (c) 2019, Intel Corporation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of Intel Corporation nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "ptunit.h" + +#include "pt_insn_decoder.h" + +#include "intel-pt.h" + + +/* A test fixture providing a decoder operating on a small buffer. */ +struct test_fixture { + /* The packet_decoder. */ + struct pt_insn_decoder decoder; + + /* The configuration. */ + struct pt_config config; + + /* The buffer it operates on. */ + uint8_t buffer[24]; + + /* The test fixture initialization and finalization functions. */ + struct ptunit_result (*init)(struct test_fixture *tfix); + struct ptunit_result (*fini)(struct test_fixture *tfix); +}; + +static struct ptunit_result tfix_init(struct test_fixture *tfix) +{ + struct pt_config *config; + uint8_t *buffer; + int errcode; + + config = &tfix->config; + buffer = tfix->buffer; + + memset(buffer, 0, sizeof(tfix->buffer)); + + pt_config_init(config); + config->begin = buffer; + config->end = buffer + sizeof(tfix->buffer); + + errcode = pt_insn_decoder_init(&tfix->decoder, config); + ptu_int_eq(errcode, 0); + + return ptu_passed(); +} + +static struct ptunit_result decoder_init_null(void) +{ + struct pt_insn_decoder decoder; + struct pt_config config; + int errcode; + + errcode = pt_insn_decoder_init(NULL, &config); + ptu_int_eq(errcode, -pte_internal); + + errcode = pt_insn_decoder_init(&decoder, NULL); + ptu_int_eq(errcode, -pte_invalid); + + return ptu_passed(); +} + +static struct ptunit_result decoder_fini_null(void) +{ + pt_insn_decoder_fini(NULL); + + return ptu_passed(); +} + +static struct ptunit_result alloc_decoder_null(void) +{ + struct pt_insn_decoder *decoder; + + decoder = pt_insn_alloc_decoder(NULL); + ptu_null(decoder); + + return ptu_passed(); +} + +static struct ptunit_result free_decoder_null(void) +{ + pt_insn_free_decoder(NULL); + + return ptu_passed(); +} + +static struct ptunit_result sync_forward_null(void) +{ + int errcode; + + errcode = pt_insn_sync_forward(NULL); + ptu_int_eq(errcode, -pte_invalid); + + return ptu_passed(); +} + +static struct ptunit_result sync_backward_null(void) +{ + int errcode; + + errcode = pt_insn_sync_backward(NULL); + ptu_int_eq(errcode, -pte_invalid); + + return ptu_passed(); +} + +static struct ptunit_result sync_set_null(void) +{ + int errcode; + + errcode = pt_insn_sync_set(NULL, 0ull); + ptu_int_eq(errcode, -pte_invalid); + + return ptu_passed(); +} + +static struct ptunit_result sync_set_eos(struct test_fixture *tfix) +{ + int errcode; + + errcode = pt_insn_sync_set(&tfix->decoder, sizeof(tfix->buffer) + 1); + ptu_int_eq(errcode, -pte_eos); + + return ptu_passed(); +} + +static struct ptunit_result get_offset_null(void) +{ + struct pt_insn_decoder decoder; + uint64_t offset; + int errcode; + + errcode = pt_insn_get_offset(NULL, &offset); + ptu_int_eq(errcode, -pte_invalid); + + errcode = pt_insn_get_offset(&decoder, NULL); + ptu_int_eq(errcode, -pte_invalid); + + return ptu_passed(); +} + +static struct ptunit_result get_offset_init(struct test_fixture *tfix) +{ + uint64_t offset; + int errcode; + + errcode = pt_insn_get_offset(&tfix->decoder, &offset); + ptu_int_eq(errcode, -pte_nosync); + + return ptu_passed(); +} + +static struct ptunit_result get_sync_offset_null(void) +{ + struct pt_insn_decoder decoder; + uint64_t offset; + int errcode; + + errcode = pt_insn_get_sync_offset(NULL, &offset); + ptu_int_eq(errcode, -pte_invalid); + + errcode = pt_insn_get_sync_offset(&decoder, NULL); + ptu_int_eq(errcode, -pte_invalid); + + return ptu_passed(); +} + +static struct ptunit_result get_config_null(void) +{ + const struct pt_config *config; + + config = pt_insn_get_config(NULL); + ptu_null(config); + + return ptu_passed(); +} + +static struct ptunit_result get_image_null(void) +{ + const struct pt_image *image; + + image = pt_insn_get_image(NULL); + ptu_null(image); + + return ptu_passed(); +} + +static struct ptunit_result set_image_null(void) +{ + struct pt_image image; + int errcode; + + errcode = pt_insn_set_image(NULL, &image); + ptu_int_eq(errcode, -pte_invalid); + + errcode = pt_insn_set_image(NULL, NULL); + ptu_int_eq(errcode, -pte_invalid); + + return ptu_passed(); +} + +static struct ptunit_result get_config(struct test_fixture *tfix) +{ + const struct pt_config *config; + + config = pt_insn_get_config(&tfix->decoder); + ptu_ptr(config); + + return ptu_passed(); +} + +static struct ptunit_result time_null(void) +{ + struct pt_insn_decoder decoder; + uint64_t time; + uint32_t lost_mtc, lost_cyc; + int errcode; + + errcode = pt_insn_time(NULL, &time, &lost_mtc, &lost_cyc); + ptu_int_eq(errcode, -pte_invalid); + + errcode = pt_insn_time(&decoder, NULL, &lost_mtc, &lost_cyc); + ptu_int_eq(errcode, -pte_invalid); + + return ptu_passed(); +} + +static struct ptunit_result cbr_null(void) +{ + struct pt_insn_decoder decoder; + uint32_t cbr; + int errcode; + + errcode = pt_insn_core_bus_ratio(NULL, &cbr); + ptu_int_eq(errcode, -pte_invalid); + + errcode = pt_insn_core_bus_ratio(&decoder, NULL); + ptu_int_eq(errcode, -pte_invalid); + + return ptu_passed(); +} + +static struct ptunit_result asid_null(void) +{ + struct pt_insn_decoder decoder; + struct pt_asid asid; + int errcode; + + errcode = pt_insn_asid(NULL, &asid, sizeof(asid)); + ptu_int_eq(errcode, -pte_invalid); + + errcode = pt_insn_asid(&decoder, NULL, sizeof(asid)); + ptu_int_eq(errcode, -pte_invalid); + + return ptu_passed(); +} + +static struct ptunit_result next_null(void) +{ + struct pt_insn_decoder decoder; + struct pt_insn insn; + int errcode; + + errcode = pt_insn_next(NULL, &insn, sizeof(insn)); + ptu_int_eq(errcode, -pte_invalid); + + errcode = pt_insn_next(&decoder, NULL, sizeof(insn)); + ptu_int_eq(errcode, -pte_invalid); + + return ptu_passed(); +} + +static struct ptunit_result event_null(void) +{ + struct pt_insn_decoder decoder; + struct pt_event event; + int errcode; + + errcode = pt_insn_event(NULL, &event, sizeof(event)); + ptu_int_eq(errcode, -pte_invalid); + + errcode = pt_insn_event(&decoder, NULL, sizeof(event)); + ptu_int_eq(errcode, -pte_invalid); + + return ptu_passed(); +} + +int main(int argc, char **argv) +{ + struct test_fixture tfix; + struct ptunit_suite suite; + + tfix.init = tfix_init; + tfix.fini = NULL; + + suite = ptunit_mk_suite(argc, argv); + + ptu_run(suite, decoder_init_null); + ptu_run(suite, decoder_fini_null); + ptu_run(suite, alloc_decoder_null); + ptu_run(suite, free_decoder_null); + + ptu_run(suite, sync_forward_null); + ptu_run(suite, sync_backward_null); + ptu_run(suite, sync_set_null); + ptu_run_f(suite, sync_set_eos, tfix); + + ptu_run(suite, get_offset_null); + ptu_run_f(suite, get_offset_init, tfix); + ptu_run(suite, get_sync_offset_null); + + ptu_run(suite, get_image_null); + ptu_run(suite, set_image_null); + + ptu_run(suite, get_config_null); + ptu_run_f(suite, get_config, tfix); + + ptu_run(suite, time_null); + ptu_run(suite, cbr_null); + ptu_run(suite, asid_null); + + ptu_run(suite, next_null); + ptu_run(suite, event_null); + + return ptunit_report(&suite); +} diff --git a/libipt/test/src/ptunit-last_ip.c b/libipt/test/src/ptunit-last_ip.c new file mode 100644 index 0000000000000..002e9c551a6ae --- /dev/null +++ b/libipt/test/src/ptunit-last_ip.c @@ -0,0 +1,374 @@ +/* + * Copyright (c) 2013-2019, Intel Corporation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of Intel Corporation nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "ptunit.h" + +#include "pt_last_ip.h" + +#include "intel-pt.h" + +#include <string.h> + + +static struct ptunit_result init(void) +{ + struct pt_last_ip last_ip; + + memset(&last_ip, 0xcd, sizeof(last_ip)); + + pt_last_ip_init(&last_ip); + + ptu_uint_eq(last_ip.ip, 0ull); + ptu_uint_eq(last_ip.have_ip, 0); + ptu_uint_eq(last_ip.suppressed, 0); + + return ptu_passed(); +} + +static struct ptunit_result init_null(void) +{ + pt_last_ip_init(NULL); + + return ptu_passed(); +} + +static struct ptunit_result status_initial(void) +{ + struct pt_last_ip last_ip; + int errcode; + + pt_last_ip_init(&last_ip); + + errcode = pt_last_ip_query(NULL, &last_ip); + ptu_int_eq(errcode, -pte_noip); + + return ptu_passed(); +} + +static struct ptunit_result status(void) +{ + struct pt_last_ip last_ip; + int errcode; + + last_ip.have_ip = 1; + last_ip.suppressed = 0; + + errcode = pt_last_ip_query(NULL, &last_ip); + ptu_int_eq(errcode, 0); + + return ptu_passed(); +} + +static struct ptunit_result status_null(void) +{ + int errcode; + + errcode = pt_last_ip_query(NULL, NULL); + ptu_int_eq(errcode, -pte_internal); + + return ptu_passed(); +} + +static struct ptunit_result status_noip(void) +{ + struct pt_last_ip last_ip; + int errcode; + + last_ip.have_ip = 0; + last_ip.suppressed = 0; + + errcode = pt_last_ip_query(NULL, &last_ip); + ptu_int_eq(errcode, -pte_noip); + + return ptu_passed(); +} + +static struct ptunit_result status_suppressed(void) +{ + struct pt_last_ip last_ip; + int errcode; + + last_ip.have_ip = 1; + last_ip.suppressed = 1; + + errcode = pt_last_ip_query(NULL, &last_ip); + ptu_int_eq(errcode, -pte_ip_suppressed); + + return ptu_passed(); +} + +static struct ptunit_result query_initial(void) +{ + struct pt_last_ip last_ip; + uint64_t ip; + int errcode; + + pt_last_ip_init(&last_ip); + + errcode = pt_last_ip_query(&ip, &last_ip); + ptu_int_eq(errcode, -pte_noip); + + return ptu_passed(); +} + +static struct ptunit_result query(void) +{ + struct pt_last_ip last_ip; + uint64_t ip, exp = 42ull; + int errcode; + + last_ip.ip = 42ull; + last_ip.have_ip = 1; + last_ip.suppressed = 0; + + errcode = pt_last_ip_query(&ip, &last_ip); + ptu_int_eq(errcode, 0); + ptu_uint_eq(last_ip.ip, exp); + + return ptu_passed(); +} + +static struct ptunit_result query_null(void) +{ + uint64_t ip = 13ull; + int errcode; + + errcode = pt_last_ip_query(&ip, NULL); + ptu_int_eq(errcode, -pte_internal); + ptu_uint_eq(ip, 13ull); + + return ptu_passed(); +} + +static struct ptunit_result query_noip(void) +{ + struct pt_last_ip last_ip; + uint64_t ip = 13ull; + int errcode; + + last_ip.ip = 42ull; + last_ip.have_ip = 0; + last_ip.suppressed = 0; + + errcode = pt_last_ip_query(&ip, &last_ip); + ptu_int_eq(errcode, -pte_noip); + ptu_uint_eq(ip, 0ull); + + return ptu_passed(); +} + +static struct ptunit_result query_suppressed(void) +{ + struct pt_last_ip last_ip; + uint64_t ip = 13ull; + int errcode; + + last_ip.ip = 42ull; + last_ip.have_ip = 1; + last_ip.suppressed = 1; + + errcode = pt_last_ip_query(&ip, &last_ip); + ptu_int_eq(errcode, -pte_ip_suppressed); + ptu_uint_eq(ip, 0ull); + + return ptu_passed(); +} + +static struct ptunit_result update_ip_suppressed(uint32_t have_ip) +{ + struct pt_last_ip last_ip; + struct pt_packet_ip packet; + int errcode; + + last_ip.ip = 42ull; + last_ip.have_ip = have_ip; + last_ip.suppressed = 0; + + packet.ipc = pt_ipc_suppressed; + packet.ip = 13ull; + + errcode = pt_last_ip_update_ip(&last_ip, &packet, NULL); + ptu_int_eq(errcode, 0); + ptu_uint_eq(last_ip.ip, 42ull); + ptu_uint_eq(last_ip.have_ip, have_ip); + ptu_uint_eq(last_ip.suppressed, 1); + + return ptu_passed(); +} + +static struct ptunit_result update_ip_upd16(uint32_t have_ip) +{ + struct pt_last_ip last_ip; + struct pt_packet_ip packet; + int errcode; + + last_ip.ip = 0xff0042ull; + last_ip.have_ip = have_ip; + last_ip.suppressed = 0; + + packet.ipc = pt_ipc_update_16; + packet.ip = 0xccc013ull; + + errcode = pt_last_ip_update_ip(&last_ip, &packet, NULL); + ptu_int_eq(errcode, 0); + ptu_uint_eq(last_ip.ip, 0xffc013ull); + ptu_uint_eq(last_ip.have_ip, 1); + ptu_uint_eq(last_ip.suppressed, 0); + + return ptu_passed(); +} + +static struct ptunit_result update_ip_upd32(uint32_t have_ip) +{ + struct pt_last_ip last_ip; + struct pt_packet_ip packet; + int errcode; + + last_ip.ip = 0xff00000420ull; + last_ip.have_ip = have_ip; + last_ip.suppressed = 0; + + packet.ipc = pt_ipc_update_32; + packet.ip = 0xcc0000c013ull; + + errcode = pt_last_ip_update_ip(&last_ip, &packet, NULL); + ptu_int_eq(errcode, 0); + ptu_uint_eq(last_ip.ip, 0xff0000c013ull); + ptu_uint_eq(last_ip.have_ip, 1); + ptu_uint_eq(last_ip.suppressed, 0); + + return ptu_passed(); +} + +static struct ptunit_result update_ip_sext48(uint32_t have_ip) +{ + struct pt_last_ip last_ip; + struct pt_packet_ip packet; + int errcode; + + last_ip.ip = 0x7fffffffffffffffull; + last_ip.have_ip = have_ip; + last_ip.suppressed = 0; + + packet.ipc = pt_ipc_sext_48; + packet.ip = 0xff00000000ffull; + + errcode = pt_last_ip_update_ip(&last_ip, &packet, NULL); + ptu_int_eq(errcode, 0); + ptu_uint_eq(last_ip.ip, 0xffffff00000000ffull); + ptu_uint_eq(last_ip.have_ip, 1); + ptu_uint_eq(last_ip.suppressed, 0); + + return ptu_passed(); +} + +static struct ptunit_result update_ip_bad_packet(uint32_t have_ip) +{ + struct pt_last_ip last_ip; + struct pt_packet_ip packet; + int errcode; + + last_ip.ip = 0x7fffffffffffffffull; + last_ip.have_ip = have_ip; + last_ip.suppressed = 0; + + packet.ipc = (enum pt_ip_compression) 0xff; + packet.ip = 0ull; + + errcode = pt_last_ip_update_ip(&last_ip, &packet, NULL); + ptu_int_eq(errcode, -pte_bad_packet); + ptu_uint_eq(last_ip.ip, 0x7fffffffffffffffull); + ptu_uint_eq(last_ip.have_ip, have_ip); + ptu_uint_eq(last_ip.suppressed, 0); + + return ptu_passed(); +} + +static struct ptunit_result update_ip_null_ip(void) +{ + struct pt_packet_ip packet; + int errcode; + + errcode = pt_last_ip_update_ip(NULL, &packet, NULL); + ptu_int_eq(errcode, -pte_internal); + + return ptu_passed(); +} + +static struct ptunit_result update_ip_null_packet(uint32_t have_ip) +{ + struct pt_last_ip last_ip; + int errcode; + + last_ip.ip = 0x7fffffffffffffffull; + last_ip.have_ip = have_ip; + last_ip.suppressed = 0; + + errcode = pt_last_ip_update_ip(&last_ip, NULL, NULL); + ptu_int_eq(errcode, -pte_internal); + ptu_uint_eq(last_ip.ip, 0x7fffffffffffffffull); + ptu_uint_eq(last_ip.have_ip, have_ip); + ptu_uint_eq(last_ip.suppressed, 0); + + return ptu_passed(); +} + +int main(int argc, char **argv) +{ + struct ptunit_suite suite; + + suite = ptunit_mk_suite(argc, argv); + + ptu_run(suite, init); + ptu_run(suite, init_null); + ptu_run(suite, status_initial); + ptu_run(suite, status); + ptu_run(suite, status_null); + ptu_run(suite, status_noip); + ptu_run(suite, status_suppressed); + ptu_run(suite, query_initial); + ptu_run(suite, query); + ptu_run(suite, query_null); + ptu_run(suite, query_noip); + ptu_run(suite, query_suppressed); + ptu_run_p(suite, update_ip_suppressed, 0); + ptu_run_p(suite, update_ip_suppressed, 1); + ptu_run_p(suite, update_ip_upd16, 0); + ptu_run_p(suite, update_ip_upd16, 1); + ptu_run_p(suite, update_ip_upd32, 0); + ptu_run_p(suite, update_ip_upd32, 1); + ptu_run_p(suite, update_ip_sext48, 0); + ptu_run_p(suite, update_ip_sext48, 1); + ptu_run_p(suite, update_ip_bad_packet, 0); + ptu_run_p(suite, update_ip_bad_packet, 1); + ptu_run(suite, update_ip_null_ip); + ptu_run_p(suite, update_ip_null_packet, 0); + ptu_run_p(suite, update_ip_null_packet, 1); + + return ptunit_report(&suite); +} diff --git a/libipt/test/src/ptunit-mapped_section.c b/libipt/test/src/ptunit-mapped_section.c new file mode 100644 index 0000000000000..2b9f563ab82ba --- /dev/null +++ b/libipt/test/src/ptunit-mapped_section.c @@ -0,0 +1,198 @@ +/* + * Copyright (c) 2014-2019, Intel Corporation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of Intel Corporation nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "ptunit.h" + +#include "pt_mapped_section.h" + +#include "intel-pt.h" + + +static struct ptunit_result begin(void) +{ + struct pt_mapped_section msec; + struct pt_section sec; + uint64_t begin; + + pt_msec_init(&msec, &sec, NULL, 0x2000ull, 0x100ull, 0x1000ull); + + begin = pt_msec_begin(&msec); + ptu_uint_eq(begin, 0x2000); + + return ptu_passed(); +} + +static struct ptunit_result end(void) +{ + struct pt_mapped_section msec; + struct pt_section sec; + uint64_t end; + + pt_msec_init(&msec, &sec, NULL, 0x2000ull, 0x100ull, 0x1000ull); + + end = pt_msec_end(&msec); + ptu_uint_eq(end, 0x3000); + + return ptu_passed(); +} + +static struct ptunit_result offset(void) +{ + struct pt_mapped_section msec; + struct pt_section sec; + uint64_t offset; + + pt_msec_init(&msec, &sec, NULL, 0x2000ull, 0x100ull, 0x1000ull); + + offset = pt_msec_offset(&msec); + ptu_uint_eq(offset, 0x100ull); + + return ptu_passed(); +} + +static struct ptunit_result size(void) +{ + struct pt_mapped_section msec; + struct pt_section sec; + uint64_t size; + + pt_msec_init(&msec, &sec, NULL, 0x2000ull, 0x100ull, 0x1000ull); + + size = pt_msec_size(&msec); + ptu_uint_eq(size, 0x1000ull); + + return ptu_passed(); +} + +static struct ptunit_result asid(void) +{ + struct pt_mapped_section msec; + struct pt_asid asid; + const struct pt_asid *pasid; + + pt_asid_init(&asid); + asid.cr3 = 0xa00000ull; + asid.vmcs = 0xb00000ull; + + pt_msec_init(&msec, NULL, &asid, 0x2000ull, 0x100ull, 0x1000ull); + + pasid = pt_msec_asid(&msec); + ptu_ptr(pasid); + ptu_uint_eq(pasid->cr3, asid.cr3); + ptu_uint_eq(pasid->vmcs, asid.vmcs); + + return ptu_passed(); +} + +static struct ptunit_result asid_null(void) +{ + struct pt_mapped_section msec; + const struct pt_asid *pasid; + + pt_msec_init(&msec, NULL, NULL, 0x2000ull, 0x100ull, 0x1000ull); + + pasid = pt_msec_asid(&msec); + ptu_ptr(pasid); + ptu_uint_eq(pasid->cr3, pt_asid_no_cr3); + ptu_uint_eq(pasid->vmcs, pt_asid_no_vmcs); + + return ptu_passed(); +} + +static struct ptunit_result map(void) +{ + struct pt_mapped_section msec; + uint64_t mapped; + + pt_msec_init(&msec, NULL, NULL, 0x2000ull, 0x100ull, 0x1000ull); + + mapped = pt_msec_map(&msec, 0x900); + ptu_uint_eq(mapped, 0x2800); + + return ptu_passed(); +} + +static struct ptunit_result unmap(void) +{ + struct pt_mapped_section msec; + uint64_t offset; + + pt_msec_init(&msec, NULL, NULL, 0x2000ull, 0x100ull, 0x1000ull); + + offset = pt_msec_unmap(&msec, 0x3000); + ptu_uint_eq(offset, 0x1100); + + return ptu_passed(); +} + +static struct ptunit_result section(void) +{ + static struct pt_section section; + struct pt_mapped_section msec; + struct pt_section *psection; + + pt_msec_init(&msec, §ion, NULL, 0x2000ull, 0x100ull, 0x1000ull); + + psection = pt_msec_section(&msec); + ptu_ptr_eq(psection, §ion); + + return ptu_passed(); +} + +static struct ptunit_result section_null(void) +{ + struct pt_mapped_section msec; + struct pt_section *psection; + + pt_msec_init(&msec, NULL, NULL, 0x2000ull, 0x100ull, 0x1000ull); + + psection = pt_msec_section(&msec); + ptu_ptr_eq(psection, NULL); + + return ptu_passed(); +} + +int main(int argc, char **argv) +{ + struct ptunit_suite suite; + + suite = ptunit_mk_suite(argc, argv); + + ptu_run(suite, begin); + ptu_run(suite, end); + ptu_run(suite, offset); + ptu_run(suite, size); + ptu_run(suite, asid); + ptu_run(suite, asid_null); + ptu_run(suite, map); + ptu_run(suite, unmap); + ptu_run(suite, section); + ptu_run(suite, section_null); + + return ptunit_report(&suite); +} diff --git a/libipt/test/src/ptunit-msec_cache.c b/libipt/test/src/ptunit-msec_cache.c new file mode 100644 index 0000000000000..7f6e979f33e43 --- /dev/null +++ b/libipt/test/src/ptunit-msec_cache.c @@ -0,0 +1,419 @@ +/* + * Copyright (c) 2017-2019, Intel Corporation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of Intel Corporation nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "ptunit.h" + +#include "pt_msec_cache.h" + +#include "intel-pt.h" + + +int pt_section_get(struct pt_section *section) +{ + uint16_t ucount; + + if (!section) + return -pte_internal; + + ucount = section->ucount + 1; + if (!ucount) + return -pte_overflow; + + section->ucount = ucount; + return 0; +} + +int pt_section_put(struct pt_section *section) +{ + uint16_t ucount; + + if (!section) + return -pte_internal; + + ucount = section->ucount; + if (!ucount) + return -pte_overflow; + + section->ucount = ucount - 1; + return 0; +} + +int pt_section_map(struct pt_section *section) +{ + uint16_t ucount, mcount; + + if (!section) + return -pte_internal; + + ucount = section->ucount; + if (!ucount) + return -pte_internal; + + mcount = section->mcount + 1; + if (!mcount) + return -pte_overflow; + + section->mcount = mcount; + return 0; +} + +int pt_section_unmap(struct pt_section *section) +{ + uint16_t ucount, mcount; + + if (!section) + return -pte_internal; + + ucount = section->ucount; + if (!ucount) + return -pte_internal; + + mcount = section->mcount; + if (!mcount) + return -pte_overflow; + + section->mcount = mcount - 1; + return 0; +} + +/* A mock image. */ +struct pt_image { + /* The section stored in the image. + * + * This is either the fixture's section or NULL. + */ + struct pt_section *section; +}; + +extern int pt_image_validate(struct pt_image *, struct pt_mapped_section *, + uint64_t, int); +extern int pt_image_find(struct pt_image *, struct pt_mapped_section *, + const struct pt_asid *, uint64_t); + +int pt_image_validate(struct pt_image *image, struct pt_mapped_section *msec, + uint64_t vaddr, int isid) +{ + struct pt_section *section; + + (void) vaddr; + (void) isid; + + if (!image || !msec) + return -pte_internal; + + section = image->section; + if (!section) + return -pte_nomap; + + if (section != msec->section) + return -pte_nomap; + + return 0; +} + +int pt_image_find(struct pt_image *image, struct pt_mapped_section *msec, + const struct pt_asid *asid, uint64_t vaddr) +{ + struct pt_section *section; + + (void) vaddr; + + if (!image || !msec || !asid) + return -pte_internal; + + section = image->section; + if (!section) + return -pte_nomap; + + if (msec->section) + return -pte_internal; + + msec->section = section; + + return pt_section_get(section); +} + +/* A test fixture providing a section and checking the use and map count. */ +struct test_fixture { + /* A test section. */ + struct pt_section section; + + /* A test cache. */ + struct pt_msec_cache mcache; + + /* A test image. */ + struct pt_image image; + + /* The test fixture initialization and finalization functions. */ + struct ptunit_result (*init)(struct test_fixture *); + struct ptunit_result (*fini)(struct test_fixture *); +}; + +static struct ptunit_result init_null(void) +{ + int status; + + status = pt_msec_cache_init(NULL); + ptu_int_eq(status, -pte_internal); + + return ptu_passed(); +} + +static struct ptunit_result fini_null(void) +{ + pt_msec_cache_fini(NULL); + + return ptu_passed(); +} + +static struct ptunit_result invalidate_null(void) +{ + int status; + + status = pt_msec_cache_invalidate(NULL); + ptu_int_eq(status, -pte_internal); + + return ptu_passed(); +} + +static struct ptunit_result read_null(void) +{ + const struct pt_mapped_section *msec; + struct pt_msec_cache mcache; + struct pt_image image; + int status; + + status = pt_msec_cache_read(NULL, &msec, &image, 0ull); + ptu_int_eq(status, -pte_internal); + + status = pt_msec_cache_read(&mcache, NULL, &image, 0ull); + ptu_int_eq(status, -pte_internal); + + status = pt_msec_cache_read(&mcache, &msec, NULL, 0ull); + ptu_int_eq(status, -pte_internal); + + return ptu_passed(); +} + +static struct ptunit_result fill_null(void) +{ + const struct pt_mapped_section *msec; + struct pt_msec_cache mcache; + struct pt_image image; + struct pt_asid asid; + int status; + + memset(&mcache, 0, sizeof(mcache)); + + status = pt_msec_cache_fill(NULL, &msec, &image, &asid, 0ull); + ptu_int_eq(status, -pte_internal); + + status = pt_msec_cache_fill(&mcache, NULL, &image, &asid, 0ull); + ptu_int_eq(status, -pte_internal); + + status = pt_msec_cache_fill(&mcache, &msec, NULL, &asid, 0ull); + ptu_int_eq(status, -pte_internal); + + status = pt_msec_cache_fill(&mcache, &msec, &image, NULL, 0ull); + ptu_int_eq(status, -pte_internal); + + return ptu_passed(); +} + +static struct ptunit_result invalidate(struct test_fixture *tfix) +{ + struct pt_section *section; + int status; + + status = pt_msec_cache_invalidate(&tfix->mcache); + ptu_int_eq(status, 0); + + section = pt_msec_section(&tfix->mcache.msec); + ptu_null(section); + + ptu_uint_eq(tfix->section.mcount, 0); + ptu_uint_eq(tfix->section.ucount, 0); + + return ptu_passed(); +} + +static struct ptunit_result read_nomap(struct test_fixture *tfix) +{ + const struct pt_mapped_section *msec; + int status; + + msec = NULL; + + status = pt_msec_cache_read(&tfix->mcache, &msec, &tfix->image, 0ull); + ptu_int_eq(status, -pte_nomap); + ptu_null(msec); + + return ptu_passed(); +} + +static struct ptunit_result read(struct test_fixture *tfix) +{ + const struct pt_mapped_section *msec; + struct pt_section *section; + int status; + + status = pt_msec_cache_read(&tfix->mcache, &msec, &tfix->image, 0ull); + ptu_int_eq(status, 0); + + ptu_ptr_eq(msec, &tfix->mcache.msec); + + section = pt_msec_section(msec); + ptu_ptr_eq(section, &tfix->section); + + return ptu_passed(); +} + +static struct ptunit_result fill_nomap(struct test_fixture *tfix) +{ + const struct pt_mapped_section *msec; + struct pt_asid asid; + struct pt_section *section; + int status; + + msec = NULL; + + status = pt_msec_cache_fill(&tfix->mcache, &msec, &tfix->image, &asid, + 0ull); + ptu_int_eq(status, -pte_nomap); + + section = pt_msec_section(&tfix->mcache.msec); + ptu_null(section); + ptu_null(msec); + + ptu_uint_eq(tfix->section.mcount, 0); + ptu_uint_eq(tfix->section.ucount, 0); + + return ptu_passed(); +} + +static struct ptunit_result fill(struct test_fixture *tfix) +{ + const struct pt_mapped_section *msec; + struct pt_section *section; + struct pt_asid asid; + int status; + + status = pt_msec_cache_fill(&tfix->mcache, &msec, &tfix->image, &asid, + 0ull); + ptu_int_eq(status, 0); + + ptu_ptr_eq(msec, &tfix->mcache.msec); + + section = pt_msec_section(msec); + ptu_ptr_eq(section, &tfix->section); + + ptu_uint_eq(section->mcount, 1); + ptu_uint_eq(section->ucount, 1); + + return ptu_passed(); +} + +static struct ptunit_result sfix_init(struct test_fixture *tfix) +{ + memset(&tfix->section, 0, sizeof(tfix->section)); + memset(&tfix->mcache, 0, sizeof(tfix->mcache)); + memset(&tfix->image, 0, sizeof(tfix->image)); + + return ptu_passed(); +} + +static struct ptunit_result ifix_init(struct test_fixture *tfix) +{ + ptu_test(sfix_init, tfix); + + tfix->image.section = &tfix->section; + + return ptu_passed(); +} + +static struct ptunit_result cfix_init(struct test_fixture *tfix) +{ + ptu_test(sfix_init, tfix); + + tfix->mcache.msec.section = &tfix->section; + + tfix->section.ucount = 1; + tfix->section.mcount = 1; + + return ptu_passed(); +} + +static struct ptunit_result cifix_init(struct test_fixture *tfix) +{ + ptu_test(cfix_init, tfix); + + tfix->image.section = &tfix->section; + + return ptu_passed(); +} + +int main(int argc, char **argv) +{ + struct ptunit_suite suite; + struct test_fixture sfix, ifix, cfix, cifix; + + sfix.init = sfix_init; + sfix.fini = NULL; + + ifix.init = ifix_init; + ifix.fini = NULL; + + cfix.init = cfix_init; + cfix.fini = NULL; + + cifix.init = cifix_init; + cifix.fini = NULL; + + suite = ptunit_mk_suite(argc, argv); + + ptu_run(suite, init_null); + ptu_run(suite, fini_null); + ptu_run(suite, invalidate_null); + ptu_run(suite, read_null); + ptu_run(suite, fill_null); + + ptu_run_f(suite, invalidate, sfix); + ptu_run_f(suite, invalidate, cfix); + + ptu_run_f(suite, read_nomap, sfix); + ptu_run_f(suite, read_nomap, ifix); + ptu_run_f(suite, read_nomap, cfix); + ptu_run_f(suite, read, cifix); + + ptu_run_f(suite, fill_nomap, sfix); + ptu_run_f(suite, fill_nomap, cfix); + ptu_run_f(suite, fill, ifix); + ptu_run_f(suite, fill, cifix); + + return ptunit_report(&suite); +} diff --git a/libipt/test/src/ptunit-packet.c b/libipt/test/src/ptunit-packet.c new file mode 100644 index 0000000000000..34df21a994b12 --- /dev/null +++ b/libipt/test/src/ptunit-packet.c @@ -0,0 +1,859 @@ +/* + * Copyright (c) 2014-2019, Intel Corporation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of Intel Corporation nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "ptunit.h" + +#include "pt_packet_decoder.h" +#include "pt_query_decoder.h" +#include "pt_encoder.h" +#include "pt_opcodes.h" + +#include "intel-pt.h" + +#include <string.h> + + +/* A test fixture providing everything needed for packet en- and de-coding. */ +struct packet_fixture { + /* The trace buffer. */ + uint8_t buffer[64]; + + /* Two packets for encoding[0] and decoding[1]. */ + struct pt_packet packet[2]; + + /* The configuration. */ + struct pt_config config; + + /* The encoder. */ + struct pt_encoder encoder; + + /* The decoder. */ + struct pt_packet_decoder decoder; + + /* The return value for an unknown decode. */ + int unknown; + + /* The test fixture initialization and finalization functions. */ + struct ptunit_result (*init)(struct packet_fixture *); + struct ptunit_result (*fini)(struct packet_fixture *); +}; + +static int pfix_decode_unknown(struct pt_packet_unknown *packet, + const struct pt_config *config, + const uint8_t *pos, void *context) +{ + struct packet_fixture *pfix; + + if (!packet || !config) + return -pte_internal; + + pfix = (struct packet_fixture *) context; + if (!pfix) + return -pte_internal; + + if (config->begin != pfix->buffer) + return -pte_internal; + + if (config->end != pfix->buffer + sizeof(pfix->buffer)) + return -pte_internal; + + if (pos != pfix->buffer) + return -pte_internal; + + packet->priv = pfix; + + return pfix->unknown; +} + +static struct ptunit_result pfix_init(struct packet_fixture *pfix) +{ + int errcode; + + memset(pfix->buffer, 0, sizeof(pfix->buffer)); + memset(pfix->packet, 0, sizeof(pfix->packet)); + memset(&pfix->config, 0, sizeof(pfix->config)); + pfix->config.size = sizeof(pfix->config); + pfix->config.begin = pfix->buffer; + pfix->config.end = pfix->buffer + sizeof(pfix->buffer); + pfix->config.decode.callback = pfix_decode_unknown; + pfix->config.decode.context = pfix; + + pt_encoder_init(&pfix->encoder, &pfix->config); + pt_pkt_decoder_init(&pfix->decoder, &pfix->config); + + errcode = pt_pkt_sync_set(&pfix->decoder, 0x0ull); + ptu_int_eq(errcode, 0); + + pfix->unknown = 0; + + return ptu_passed(); +} + +static struct ptunit_result pfix_fini(struct packet_fixture *pfix) +{ + pt_encoder_fini(&pfix->encoder); + pt_pkt_decoder_fini(&pfix->decoder); + + return ptu_passed(); +} + +static struct ptunit_result ptu_pkt_eq(const struct pt_packet *enc, + const struct pt_packet *dec) +{ + const uint8_t *renc, *rdec; + size_t byte; + + ptu_ptr(enc); + ptu_ptr(dec); + + renc = (const uint8_t *) enc; + rdec = (const uint8_t *) dec; + + for (byte = 0; byte < sizeof(*enc); ++byte) + ptu_uint_eq(renc[byte], rdec[byte]); + + return ptu_passed(); +} + +static struct ptunit_result pfix_test(struct packet_fixture *pfix) +{ + int size; + + size = pt_enc_next(&pfix->encoder, &pfix->packet[0]); + ptu_int_gt(size, 0); + + pfix->packet[0].size = (uint8_t) size; + + size = pt_pkt_next(&pfix->decoder, &pfix->packet[1], + sizeof(pfix->packet[1])); + ptu_int_gt(size, 0); + + return ptu_pkt_eq(&pfix->packet[0], &pfix->packet[1]); +} + +static struct ptunit_result no_payload(struct packet_fixture *pfix, + enum pt_packet_type type) +{ + pfix->packet[0].type = type; + + ptu_test(pfix_test, pfix); + + return ptu_passed(); +} + +static struct ptunit_result unknown(struct packet_fixture *pfix, int exp) +{ + int size; + + pfix->buffer[0] = pt_opc_bad; + pfix->unknown = exp; + + size = pt_pkt_next(&pfix->decoder, &pfix->packet[1], + sizeof(pfix->packet[1])); + ptu_int_eq(size, pfix->unknown); + + if (size >= 0) { + ptu_int_eq(pfix->packet[1].type, ppt_unknown); + ptu_uint_eq(pfix->packet[1].size, (uint8_t) size); + ptu_ptr_eq(pfix->packet[1].payload.unknown.packet, + pfix->buffer); + ptu_ptr_eq(pfix->packet[1].payload.unknown.priv, pfix); + } + + return ptu_passed(); +} + +static struct ptunit_result unknown_ext(struct packet_fixture *pfix, int exp) +{ + int size; + + pfix->buffer[0] = pt_opc_ext; + pfix->buffer[1] = pt_ext_bad; + pfix->unknown = exp; + + size = pt_pkt_next(&pfix->decoder, &pfix->packet[1], + sizeof(pfix->packet[1])); + ptu_int_eq(size, pfix->unknown); + + if (size >= 0) { + ptu_int_eq(pfix->packet[1].type, ppt_unknown); + ptu_uint_eq(pfix->packet[1].size, (uint8_t) size); + ptu_ptr_eq(pfix->packet[1].payload.unknown.packet, + pfix->buffer); + ptu_ptr_eq(pfix->packet[1].payload.unknown.priv, pfix); + } + + return ptu_passed(); +} + +static struct ptunit_result unknown_ext2(struct packet_fixture *pfix, int exp) +{ + int size; + + pfix->buffer[0] = pt_opc_ext; + pfix->buffer[1] = pt_ext_ext2; + pfix->buffer[2] = pt_ext2_bad; + pfix->unknown = exp; + + size = pt_pkt_next(&pfix->decoder, &pfix->packet[1], + sizeof(pfix->packet[1])); + ptu_int_eq(size, exp); + + if (exp >= 0) { + ptu_int_eq(pfix->packet[1].type, ppt_unknown); + ptu_uint_eq(pfix->packet[1].size, (uint8_t) size); + ptu_ptr_eq(pfix->packet[1].payload.unknown.packet, + pfix->buffer); + ptu_ptr_eq(pfix->packet[1].payload.unknown.priv, pfix); + } + + return ptu_passed(); +} + +static struct ptunit_result tnt_8(struct packet_fixture *pfix) +{ + pfix->packet[0].type = ppt_tnt_8; + pfix->packet[0].payload.tnt.bit_size = 4; + pfix->packet[0].payload.tnt.payload = 0x5ull; + + ptu_test(pfix_test, pfix); + + return ptu_passed(); +} + +static struct ptunit_result tnt_64(struct packet_fixture *pfix) +{ + pfix->packet[0].type = ppt_tnt_64; + pfix->packet[0].payload.tnt.bit_size = 23; + pfix->packet[0].payload.tnt.payload = 0xabcdeull; + + ptu_test(pfix_test, pfix); + + return ptu_passed(); +} + +static struct ptunit_result ip(struct packet_fixture *pfix, + enum pt_packet_type type, + enum pt_ip_compression ipc, + uint64_t ip) +{ + pfix->packet[0].type = type; + pfix->packet[0].payload.ip.ipc = ipc; + pfix->packet[0].payload.ip.ip = ip; + + ptu_test(pfix_test, pfix); + + return ptu_passed(); +} + +static struct ptunit_result mode_exec(struct packet_fixture *pfix, + enum pt_exec_mode mode) +{ + struct pt_packet_mode_exec packet; + + packet = pt_set_exec_mode(mode); + + pfix->packet[0].type = ppt_mode; + pfix->packet[0].payload.mode.leaf = pt_mol_exec; + pfix->packet[0].payload.mode.bits.exec.csl = packet.csl; + pfix->packet[0].payload.mode.bits.exec.csd = packet.csd; + + ptu_test(pfix_test, pfix); + + return ptu_passed(); +} + +static struct ptunit_result mode_tsx(struct packet_fixture *pfix) +{ + pfix->packet[0].type = ppt_mode; + pfix->packet[0].payload.mode.leaf = pt_mol_tsx; + pfix->packet[0].payload.mode.bits.tsx.intx = 1; + + ptu_test(pfix_test, pfix); + + return ptu_passed(); +} + +static struct ptunit_result pip(struct packet_fixture *pfix) +{ + pfix->packet[0].type = ppt_pip; + pfix->packet[0].payload.pip.cr3 = 0x4200ull; + pfix->packet[0].payload.pip.nr = 1; + + ptu_test(pfix_test, pfix); + + return ptu_passed(); +} + +static struct ptunit_result tsc(struct packet_fixture *pfix) +{ + pfix->packet[0].type = ppt_tsc; + pfix->packet[0].payload.tsc.tsc = 0x42ull; + + ptu_test(pfix_test, pfix); + + return ptu_passed(); +} + +static struct ptunit_result cbr(struct packet_fixture *pfix) +{ + pfix->packet[0].type = ppt_cbr; + pfix->packet[0].payload.cbr.ratio = 0x23; + + ptu_test(pfix_test, pfix); + + return ptu_passed(); +} + +static struct ptunit_result tma(struct packet_fixture *pfix) +{ + pfix->packet[0].type = ppt_tma; + pfix->packet[0].payload.tma.ctc = 0x42; + pfix->packet[0].payload.tma.fc = 0x123; + + ptu_test(pfix_test, pfix); + + return ptu_passed(); +} + +static struct ptunit_result tma_bad(struct packet_fixture *pfix) +{ + int errcode; + + pfix->packet[0].type = ppt_tma; + pfix->packet[0].payload.tma.ctc = 0x42; + pfix->packet[0].payload.tma.fc = 0x200; + + errcode = pt_enc_next(&pfix->encoder, &pfix->packet[0]); + ptu_int_eq(errcode, -pte_bad_packet); + + return ptu_passed(); +} + +static struct ptunit_result mtc(struct packet_fixture *pfix) +{ + pfix->packet[0].type = ppt_mtc; + pfix->packet[0].payload.mtc.ctc = 0x23; + + ptu_test(pfix_test, pfix); + + return ptu_passed(); +} + +static struct ptunit_result cyc(struct packet_fixture *pfix) +{ + pfix->packet[0].type = ppt_cyc; + pfix->packet[0].payload.cyc.value = 0x23; + + ptu_test(pfix_test, pfix); + + return ptu_passed(); +} + +static struct ptunit_result vmcs(struct packet_fixture *pfix) +{ + pfix->packet[0].type = ppt_vmcs; + pfix->packet[0].payload.vmcs.base = 0xabcdef000ull; + + ptu_test(pfix_test, pfix); + + return ptu_passed(); +} + +static struct ptunit_result mnt(struct packet_fixture *pfix) +{ + pfix->packet[0].type = ppt_mnt; + pfix->packet[0].payload.mnt.payload = 0x1234567890abcdefull; + + ptu_test(pfix_test, pfix); + + return ptu_passed(); +} + +static struct ptunit_result exstop(struct packet_fixture *pfix, int ip) +{ + pfix->packet[0].type = ppt_exstop; + pfix->packet[0].payload.exstop.ip = ip ? 1 : 0; + + ptu_test(pfix_test, pfix); + + return ptu_passed(); +} + +static struct ptunit_result mwait(struct packet_fixture *pfix) +{ + pfix->packet[0].type = ppt_mwait; + pfix->packet[0].payload.mwait.hints = 0xc; + pfix->packet[0].payload.mwait.ext = 0x1; + + ptu_test(pfix_test, pfix); + + return ptu_passed(); +} + +static struct ptunit_result pwre(struct packet_fixture *pfix) +{ + pfix->packet[0].type = ppt_pwre; + pfix->packet[0].payload.pwre.state = 0x0; + pfix->packet[0].payload.pwre.sub_state = 0x3; + pfix->packet[0].payload.pwre.hw = 1; + + ptu_test(pfix_test, pfix); + + return ptu_passed(); +} + +static struct ptunit_result pwrx(struct packet_fixture *pfix) +{ + pfix->packet[0].type = ppt_pwrx; + pfix->packet[0].payload.pwrx.last = 0x3; + pfix->packet[0].payload.pwrx.deepest = 0xa; + pfix->packet[0].payload.pwrx.store = 1; + + ptu_test(pfix_test, pfix); + + return ptu_passed(); +} + +static struct ptunit_result ptw(struct packet_fixture *pfix, uint8_t plc, + int ip) +{ + uint64_t pl, mask; + int size; + + size = pt_ptw_size(plc); + ptu_int_gt(size, 0); + + pl = 0x1234567890abcdefull; + + ptu_uint_le((size_t) size, sizeof(mask)); + mask = ~0ull >> ((sizeof(mask) - (size_t) size) * 8); + + pfix->packet[0].type = ppt_ptw; + pfix->packet[0].payload.ptw.payload = pl & mask; + pfix->packet[0].payload.ptw.plc = plc; + pfix->packet[0].payload.ptw.ip = ip ? 1 : 0; + + ptu_test(pfix_test, pfix); + + return ptu_passed(); +} + +static struct ptunit_result cutoff(struct packet_fixture *pfix, + enum pt_packet_type type) +{ + int size; + + pfix->packet[0].type = type; + + size = pt_enc_next(&pfix->encoder, &pfix->packet[0]); + ptu_int_gt(size, 0); + + pfix->decoder.config.end = pfix->encoder.pos - 1; + + size = pt_pkt_next(&pfix->decoder, &pfix->packet[1], + sizeof(pfix->packet[1])); + ptu_int_eq(size, -pte_eos); + + return ptu_passed(); +} + +static struct ptunit_result cutoff_ip(struct packet_fixture *pfix, + enum pt_packet_type type) +{ + int size; + + pfix->packet[0].type = type; + pfix->packet[0].payload.ip.ipc = pt_ipc_sext_48; + + size = pt_enc_next(&pfix->encoder, &pfix->packet[0]); + ptu_int_gt(size, 0); + + pfix->decoder.config.end = pfix->encoder.pos - 1; + + size = pt_pkt_next(&pfix->decoder, &pfix->packet[1], + sizeof(pfix->packet[1])); + ptu_int_eq(size, -pte_eos); + + return ptu_passed(); +} + +static struct ptunit_result cutoff_cyc(struct packet_fixture *pfix) +{ + int size; + + pfix->packet[0].type = ppt_cyc; + pfix->packet[0].payload.cyc.value = 0xa8; + + size = pt_enc_next(&pfix->encoder, &pfix->packet[0]); + ptu_int_gt(size, 0); + + pfix->decoder.config.end = pfix->encoder.pos - 1; + + size = pt_pkt_next(&pfix->decoder, &pfix->packet[1], + sizeof(pfix->packet[1])); + ptu_int_eq(size, -pte_eos); + + return ptu_passed(); +} + +static struct ptunit_result cutoff_mode(struct packet_fixture *pfix, + enum pt_mode_leaf leaf) +{ + int size; + + pfix->packet[0].type = ppt_mode; + pfix->packet[0].payload.mode.leaf = leaf; + + size = pt_enc_next(&pfix->encoder, &pfix->packet[0]); + ptu_int_gt(size, 0); + + pfix->decoder.config.end = pfix->encoder.pos - 1; + + size = pt_pkt_next(&pfix->decoder, &pfix->packet[1], + sizeof(pfix->packet[1])); + ptu_int_eq(size, -pte_eos); + + return ptu_passed(); +} + +int main(int argc, char **argv) +{ + struct packet_fixture pfix; + struct ptunit_suite suite; + + pfix.init = pfix_init; + pfix.fini = pfix_fini; + + suite = ptunit_mk_suite(argc, argv); + + ptu_run_fp(suite, no_payload, pfix, ppt_pad); + ptu_run_fp(suite, no_payload, pfix, ppt_psb); + ptu_run_fp(suite, no_payload, pfix, ppt_ovf); + ptu_run_fp(suite, no_payload, pfix, ppt_psbend); + ptu_run_fp(suite, no_payload, pfix, ppt_stop); + + ptu_run_fp(suite, unknown, pfix, 4); + ptu_run_fp(suite, unknown, pfix, -pte_nomem); + ptu_run_fp(suite, unknown_ext, pfix, 4); + ptu_run_fp(suite, unknown_ext, pfix, -pte_nomem); + ptu_run_fp(suite, unknown_ext2, pfix, 4); + ptu_run_fp(suite, unknown_ext2, pfix, -pte_nomem); + + ptu_run_f(suite, tnt_8, pfix); + ptu_run_f(suite, tnt_64, pfix); + + ptu_run_fp(suite, ip, pfix, ppt_tip, pt_ipc_suppressed, 0x0ull); + ptu_run_fp(suite, ip, pfix, ppt_tip, pt_ipc_update_16, 0x42ull); + ptu_run_fp(suite, ip, pfix, ppt_tip, pt_ipc_update_32, 0x4200ull); + ptu_run_fp(suite, ip, pfix, ppt_tip, pt_ipc_update_48, 0x4200ull); + ptu_run_fp(suite, ip, pfix, ppt_tip, pt_ipc_sext_48, 0x42ull); + ptu_run_fp(suite, ip, pfix, ppt_tip, pt_ipc_full, 0x42ull); + + ptu_run_fp(suite, ip, pfix, ppt_tip, pt_ipc_suppressed, 0x0ull); + ptu_run_fp(suite, ip, pfix, ppt_tip, pt_ipc_update_16, 0x42ull); + ptu_run_fp(suite, ip, pfix, ppt_tip, pt_ipc_update_32, 0x4200ull); + ptu_run_fp(suite, ip, pfix, ppt_tip, pt_ipc_update_48, 0x4200ull); + ptu_run_fp(suite, ip, pfix, ppt_tip, pt_ipc_sext_48, 0x42ull); + ptu_run_fp(suite, ip, pfix, ppt_tip, pt_ipc_full, 0x42ull); + + ptu_run_fp(suite, ip, pfix, ppt_tip_pge, pt_ipc_suppressed, 0x0ull); + ptu_run_fp(suite, ip, pfix, ppt_tip_pge, pt_ipc_update_16, 0x42ull); + ptu_run_fp(suite, ip, pfix, ppt_tip_pge, pt_ipc_update_32, 0x4200ull); + ptu_run_fp(suite, ip, pfix, ppt_tip_pge, pt_ipc_update_48, 0x4200ull); + ptu_run_fp(suite, ip, pfix, ppt_tip_pge, pt_ipc_sext_48, 0x42ull); + ptu_run_fp(suite, ip, pfix, ppt_tip_pge, pt_ipc_full, 0x42ull); + + ptu_run_fp(suite, ip, pfix, ppt_tip_pgd, pt_ipc_suppressed, 0x0ull); + ptu_run_fp(suite, ip, pfix, ppt_tip_pgd, pt_ipc_update_16, 0x42ull); + ptu_run_fp(suite, ip, pfix, ppt_tip_pgd, pt_ipc_update_32, 0x4200ull); + ptu_run_fp(suite, ip, pfix, ppt_tip_pgd, pt_ipc_update_48, 0x4200ull); + ptu_run_fp(suite, ip, pfix, ppt_tip_pgd, pt_ipc_sext_48, 0x42ull); + ptu_run_fp(suite, ip, pfix, ppt_tip_pgd, pt_ipc_full, 0x42ull); + + ptu_run_fp(suite, ip, pfix, ppt_fup, pt_ipc_suppressed, 0x0ull); + ptu_run_fp(suite, ip, pfix, ppt_fup, pt_ipc_update_16, 0x42ull); + ptu_run_fp(suite, ip, pfix, ppt_fup, pt_ipc_update_32, 0x4200ull); + ptu_run_fp(suite, ip, pfix, ppt_fup, pt_ipc_update_48, 0x4200ull); + ptu_run_fp(suite, ip, pfix, ppt_fup, pt_ipc_sext_48, 0x42ull); + ptu_run_fp(suite, ip, pfix, ppt_fup, pt_ipc_full, 0x42ull); + + ptu_run_fp(suite, mode_exec, pfix, ptem_16bit); + ptu_run_fp(suite, mode_exec, pfix, ptem_32bit); + ptu_run_fp(suite, mode_exec, pfix, ptem_64bit); + ptu_run_f(suite, mode_tsx, pfix); + + ptu_run_f(suite, pip, pfix); + ptu_run_f(suite, tsc, pfix); + ptu_run_f(suite, cbr, pfix); + ptu_run_f(suite, tma, pfix); + ptu_run_f(suite, tma_bad, pfix); + ptu_run_f(suite, mtc, pfix); + ptu_run_f(suite, cyc, pfix); + ptu_run_f(suite, vmcs, pfix); + ptu_run_f(suite, mnt, pfix); + ptu_run_fp(suite, exstop, pfix, 0); + ptu_run_fp(suite, exstop, pfix, 1); + ptu_run_f(suite, mwait, pfix); + ptu_run_f(suite, pwre, pfix); + ptu_run_f(suite, pwrx, pfix); + ptu_run_fp(suite, ptw, pfix, 0, 1); + ptu_run_fp(suite, ptw, pfix, 1, 0); + + ptu_run_fp(suite, cutoff, pfix, ppt_psb); + ptu_run_fp(suite, cutoff_ip, pfix, ppt_tip); + ptu_run_fp(suite, cutoff_ip, pfix, ppt_tip_pge); + ptu_run_fp(suite, cutoff_ip, pfix, ppt_tip_pgd); + ptu_run_fp(suite, cutoff_ip, pfix, ppt_fup); + ptu_run_fp(suite, cutoff, pfix, ppt_ovf); + ptu_run_fp(suite, cutoff, pfix, ppt_psbend); + ptu_run_fp(suite, cutoff, pfix, ppt_tnt_64); + ptu_run_fp(suite, cutoff, pfix, ppt_tsc); + ptu_run_fp(suite, cutoff, pfix, ppt_cbr); + ptu_run_fp(suite, cutoff, pfix, ppt_tma); + ptu_run_fp(suite, cutoff, pfix, ppt_mtc); + ptu_run_f(suite, cutoff_cyc, pfix); + ptu_run_fp(suite, cutoff_mode, pfix, pt_mol_exec); + ptu_run_fp(suite, cutoff_mode, pfix, pt_mol_tsx); + ptu_run_fp(suite, cutoff, pfix, ppt_vmcs); + ptu_run_fp(suite, cutoff, pfix, ppt_mnt); + ptu_run_fp(suite, cutoff, pfix, ppt_exstop); + ptu_run_fp(suite, cutoff, pfix, ppt_mwait); + ptu_run_fp(suite, cutoff, pfix, ppt_pwre); + ptu_run_fp(suite, cutoff, pfix, ppt_pwrx); + ptu_run_fp(suite, cutoff, pfix, ppt_ptw); + + return ptunit_report(&suite); +} + + +/* Dummy decode functions to satisfy link dependencies. + * + * As a nice side-effect, we will know if we need to add more tests when + * adding new decoder functions. + */ +struct pt_query_decoder; + +int pt_qry_decode_unknown(struct pt_query_decoder *d) +{ + (void) d; + + return -pte_internal; +} +int pt_qry_decode_pad(struct pt_query_decoder *d) +{ + (void) d; + + return -pte_internal; +} +int pt_qry_decode_psb(struct pt_query_decoder *d) +{ + (void) d; + + return -pte_internal; +} +int pt_qry_decode_tip(struct pt_query_decoder *d) +{ + (void) d; + + return -pte_internal; +} +int pt_qry_decode_tnt_8(struct pt_query_decoder *d) +{ + (void) d; + + return -pte_internal; +} +int pt_qry_decode_tnt_64(struct pt_query_decoder *d) +{ + (void) d; + + return -pte_internal; +} +int pt_qry_decode_tip_pge(struct pt_query_decoder *d) +{ + (void) d; + + return -pte_internal; +} +int pt_qry_decode_tip_pgd(struct pt_query_decoder *d) +{ + (void) d; + + return -pte_internal; +} +int pt_qry_decode_fup(struct pt_query_decoder *d) +{ + (void) d; + + return -pte_internal; +} +int pt_qry_header_fup(struct pt_query_decoder *d) +{ + (void) d; + + return -pte_internal; +} +int pt_qry_decode_pip(struct pt_query_decoder *d) +{ + (void) d; + + return -pte_internal; +} +int pt_qry_header_pip(struct pt_query_decoder *d) +{ + (void) d; + + return -pte_internal; +} +int pt_qry_decode_ovf(struct pt_query_decoder *d) +{ + (void) d; + + return -pte_internal; +} +int pt_qry_decode_mode(struct pt_query_decoder *d) +{ + (void) d; + + return -pte_internal; +} +int pt_qry_header_mode(struct pt_query_decoder *d) +{ + (void) d; + + return -pte_internal; +} +int pt_qry_decode_psbend(struct pt_query_decoder *d) +{ + (void) d; + + return -pte_internal; +} +int pt_qry_decode_tsc(struct pt_query_decoder *d) +{ + (void) d; + + return -pte_internal; +} +int pt_qry_header_tsc(struct pt_query_decoder *d) +{ + (void) d; + + return -pte_internal; +} +int pt_qry_decode_cbr(struct pt_query_decoder *d) +{ + (void) d; + + return -pte_internal; +} +int pt_qry_header_cbr(struct pt_query_decoder *d) +{ + (void) d; + + return -pte_internal; +} +int pt_qry_decode_tma(struct pt_query_decoder *d) +{ + (void) d; + + return -pte_internal; +} +int pt_qry_decode_mtc(struct pt_query_decoder *d) +{ + (void) d; + + return -pte_internal; +} +int pt_qry_decode_cyc(struct pt_query_decoder *d) +{ + (void) d; + + return -pte_internal; +} +int pt_qry_decode_stop(struct pt_query_decoder *d) +{ + (void) d; + + return -pte_internal; +} +int pt_qry_decode_vmcs(struct pt_query_decoder *d) +{ + (void) d; + + return -pte_internal; +} +int pt_qry_header_vmcs(struct pt_query_decoder *d) +{ + (void) d; + + return -pte_internal; +} +int pt_qry_decode_mnt(struct pt_query_decoder *d) +{ + (void) d; + + return -pte_internal; +} +int pt_qry_header_mnt(struct pt_query_decoder *d) +{ + (void) d; + + return -pte_internal; +} +int pt_qry_decode_exstop(struct pt_query_decoder *d) +{ + (void) d; + + return -pte_internal; +} +int pt_qry_decode_mwait(struct pt_query_decoder *d) +{ + (void) d; + + return -pte_internal; +} +int pt_qry_decode_pwre(struct pt_query_decoder *d) +{ + (void) d; + + return -pte_internal; +} +int pt_qry_decode_pwrx(struct pt_query_decoder *d) +{ + (void) d; + + return -pte_internal; +} +int pt_qry_decode_ptw(struct pt_query_decoder *d) +{ + (void) d; + + return -pte_internal; +} diff --git a/libipt/test/src/ptunit-packet_decoder.c b/libipt/test/src/ptunit-packet_decoder.c new file mode 100644 index 0000000000000..5659f9acec337 --- /dev/null +++ b/libipt/test/src/ptunit-packet_decoder.c @@ -0,0 +1,274 @@ +/* + * Copyright (c) 2019, Intel Corporation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of Intel Corporation nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "ptunit.h" + +#include "pt_packet_decoder.h" + +#include "intel-pt.h" + + +/* A test fixture providing a decoder operating on a small buffer. */ +struct test_fixture { + /* The packet_decoder. */ + struct pt_packet_decoder decoder; + + /* The configuration. */ + struct pt_config config; + + /* The buffer it operates on. */ + uint8_t buffer[24]; + + /* The test fixture initialization and finalization functions. */ + struct ptunit_result (*init)(struct test_fixture *tfix); + struct ptunit_result (*fini)(struct test_fixture *tfix); +}; + +static struct ptunit_result tfix_init(struct test_fixture *tfix) +{ + struct pt_config *config; + uint8_t *buffer; + int errcode; + + config = &tfix->config; + buffer = tfix->buffer; + + memset(buffer, 0, sizeof(tfix->buffer)); + + pt_config_init(config); + config->begin = buffer; + config->end = buffer + sizeof(tfix->buffer); + + errcode = pt_pkt_decoder_init(&tfix->decoder, config); + ptu_int_eq(errcode, 0); + + return ptu_passed(); +} + +static struct ptunit_result decoder_init_null(void) +{ + struct pt_packet_decoder decoder; + struct pt_config config; + int errcode; + + errcode = pt_pkt_decoder_init(NULL, &config); + ptu_int_eq(errcode, -pte_invalid); + + errcode = pt_pkt_decoder_init(&decoder, NULL); + ptu_int_eq(errcode, -pte_invalid); + + return ptu_passed(); +} + +static struct ptunit_result decoder_fini_null(void) +{ + pt_pkt_decoder_fini(NULL); + + return ptu_passed(); +} + +static struct ptunit_result alloc_decoder_null(void) +{ + struct pt_packet_decoder *decoder; + + decoder = pt_pkt_alloc_decoder(NULL); + ptu_null(decoder); + + return ptu_passed(); +} + +static struct ptunit_result free_decoder_null(void) +{ + pt_pkt_free_decoder(NULL); + + return ptu_passed(); +} + +static struct ptunit_result sync_forward_null(void) +{ + int errcode; + + errcode = pt_pkt_sync_forward(NULL); + ptu_int_eq(errcode, -pte_invalid); + + return ptu_passed(); +} + +static struct ptunit_result sync_backward_null(void) +{ + int errcode; + + errcode = pt_pkt_sync_backward(NULL); + ptu_int_eq(errcode, -pte_invalid); + + return ptu_passed(); +} + +static struct ptunit_result sync_set_null(void) +{ + int errcode; + + errcode = pt_pkt_sync_set(NULL, 0ull); + ptu_int_eq(errcode, -pte_invalid); + + return ptu_passed(); +} + +static struct ptunit_result sync_set_eos(struct test_fixture *tfix) +{ + int errcode; + + errcode = pt_pkt_sync_set(&tfix->decoder, sizeof(tfix->buffer) + 1); + ptu_int_eq(errcode, -pte_eos); + + return ptu_passed(); +} + +static struct ptunit_result get_offset_null(void) +{ + struct pt_packet_decoder decoder; + uint64_t offset; + int errcode; + + errcode = pt_pkt_get_offset(NULL, &offset); + ptu_int_eq(errcode, -pte_invalid); + + errcode = pt_pkt_get_offset(&decoder, NULL); + ptu_int_eq(errcode, -pte_invalid); + + return ptu_passed(); +} + +static struct ptunit_result get_offset_init(struct test_fixture *tfix) +{ + uint64_t offset; + int errcode; + + errcode = pt_pkt_get_offset(&tfix->decoder, &offset); + ptu_int_eq(errcode, -pte_nosync); + + return ptu_passed(); +} + +static struct ptunit_result sync_set_get_offset(struct test_fixture *tfix) +{ + uint64_t offset; + int errcode; + + errcode = pt_pkt_sync_set(&tfix->decoder, 1ull); + ptu_int_eq(errcode, 0); + + errcode = pt_pkt_get_offset(&tfix->decoder, &offset); + ptu_int_eq(errcode, 0); + ptu_uint_eq(offset, 1ull); + + return ptu_passed(); +} + +static struct ptunit_result get_sync_offset_null(void) +{ + struct pt_packet_decoder decoder; + uint64_t offset; + int errcode; + + errcode = pt_pkt_get_sync_offset(NULL, &offset); + ptu_int_eq(errcode, -pte_invalid); + + errcode = pt_pkt_get_sync_offset(&decoder, NULL); + ptu_int_eq(errcode, -pte_invalid); + + return ptu_passed(); +} + +static struct ptunit_result get_config_null(void) +{ + const struct pt_config *config; + + config = pt_pkt_get_config(NULL); + ptu_null(config); + + return ptu_passed(); +} + +static struct ptunit_result get_config(struct test_fixture *tfix) +{ + const struct pt_config *config; + + config = pt_pkt_get_config(&tfix->decoder); + ptu_ptr(config); + + return ptu_passed(); +} + +static struct ptunit_result next_null(void) +{ + struct pt_packet_decoder decoder; + struct pt_packet packet; + int errcode; + + errcode = pt_pkt_next(NULL, &packet, sizeof(packet)); + ptu_int_eq(errcode, -pte_invalid); + + errcode = pt_pkt_next(&decoder, NULL, sizeof(packet)); + ptu_int_eq(errcode, -pte_invalid); + + return ptu_passed(); +} + +int main(int argc, char **argv) +{ + struct test_fixture tfix; + struct ptunit_suite suite; + + tfix.init = tfix_init; + tfix.fini = NULL; + + suite = ptunit_mk_suite(argc, argv); + + ptu_run(suite, decoder_init_null); + ptu_run(suite, decoder_fini_null); + ptu_run(suite, alloc_decoder_null); + ptu_run(suite, free_decoder_null); + + ptu_run(suite, sync_forward_null); + ptu_run(suite, sync_backward_null); + ptu_run(suite, sync_set_null); + ptu_run_f(suite, sync_set_eos, tfix); + + ptu_run(suite, get_offset_null); + ptu_run_f(suite, get_offset_init, tfix); + ptu_run_f(suite, sync_set_get_offset, tfix); + ptu_run(suite, get_sync_offset_null); + + ptu_run(suite, get_config_null); + ptu_run_f(suite, get_config, tfix); + + ptu_run(suite, next_null); + + return ptunit_report(&suite); +} diff --git a/libipt/test/src/ptunit-query.c b/libipt/test/src/ptunit-query.c new file mode 100644 index 0000000000000..e22a3e9896bc3 --- /dev/null +++ b/libipt/test/src/ptunit-query.c @@ -0,0 +1,2873 @@ +/* + * Copyright (c) 2013-2019, Intel Corporation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of Intel Corporation nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "ptunit.h" + +#include "pt_last_ip.h" +#include "pt_decoder_function.h" +#include "pt_query_decoder.h" +#include "pt_encoder.h" +#include "pt_opcodes.h" + + +/* A query testing fixture. */ + +struct ptu_decoder_fixture { + /* The test fixture initialization and finalization functions. */ + struct ptunit_result (*init)(struct ptu_decoder_fixture *); + struct ptunit_result (*fini)(struct ptu_decoder_fixture *); + + /* Encode an optional header for the test to read over. */ + struct ptunit_result (*header)(struct ptu_decoder_fixture *); + + /* The trace buffer. */ + uint8_t buffer[1024]; + + /* The configuration under test. */ + struct pt_config config; + + /* A encoder and query decoder for the above configuration. */ + struct pt_encoder encoder; + struct pt_query_decoder decoder; + + /* For tracking last-ip in tests. */ + struct pt_last_ip last_ip; +}; + +/* An invalid address. */ +static const uint64_t pt_dfix_bad_ip = (1ull << 62) - 1ull; + +/* A sign-extended address. */ +static const uint64_t pt_dfix_sext_ip = 0xffffff00ff00ff00ull; + +/* The highest possible address. */ +static const uint64_t pt_dfix_max_ip = (1ull << 47) - 1ull; + +/* The highest possible cr3 value. */ +static const uint64_t pt_dfix_max_cr3 = ((1ull << 47) - 1ull) & ~0x1full; + +/* Synchronize the decoder at the beginning of the trace stream, avoiding the + * initial PSB header. + */ +static struct ptunit_result ptu_sync_decoder(struct pt_query_decoder *decoder) +{ + ptu_ptr(decoder); + decoder->enabled = 1; + + (void) pt_df_fetch(&decoder->next, decoder->pos, &decoder->config); + return ptu_passed(); +} + +/* Cut off the last encoded packet. */ +static struct ptunit_result cutoff(struct pt_query_decoder *decoder, + const struct pt_encoder *encoder) +{ + uint8_t *pos; + + ptu_ptr(decoder); + ptu_ptr(encoder); + + pos = encoder->pos; + ptu_ptr(pos); + + pos -= 1; + ptu_ptr_le(decoder->config.begin, pos); + + decoder->config.end = pos; + return ptu_passed(); +} + +static struct ptunit_result indir_not_synced(struct ptu_decoder_fixture *dfix) +{ + struct pt_query_decoder *decoder = &dfix->decoder; + uint64_t ip = pt_dfix_bad_ip, addr = ip; + int errcode; + + errcode = pt_qry_indirect_branch(decoder, &addr); + ptu_int_eq(errcode, -pte_nosync); + ptu_uint_eq(addr, ip); + + return ptu_passed(); +} + +static struct ptunit_result cond_not_synced(struct ptu_decoder_fixture *dfix) +{ + struct pt_query_decoder *decoder = &dfix->decoder; + int errcode, tnt = 0xbc, taken = tnt; + + errcode = pt_qry_cond_branch(decoder, &taken); + ptu_int_eq(errcode, -pte_nosync); + ptu_int_eq(taken, tnt); + + return ptu_passed(); +} + +static struct ptunit_result event_not_synced(struct ptu_decoder_fixture *dfix) +{ + struct pt_query_decoder *decoder = &dfix->decoder; + struct pt_event event; + int errcode; + + errcode = pt_qry_event(decoder, &event, sizeof(event)); + ptu_int_eq(errcode, -pte_nosync); + + return ptu_passed(); +} + +static struct ptunit_result sync_backward(struct ptu_decoder_fixture *dfix) +{ + struct pt_query_decoder *decoder = &dfix->decoder; + struct pt_encoder *encoder = &dfix->encoder; + uint64_t sync[3], offset, ip; + int errcode; + + /* Check that we can use repeated pt_qry_sync_backward() to iterate over + * synchronization points in backwards order. + */ + + errcode = pt_enc_get_offset(encoder, &sync[0]); + ptu_int_ge(errcode, 0); + + pt_encode_psb(encoder); + pt_encode_mode_exec(encoder, ptem_64bit); + pt_encode_psbend(encoder); + + errcode = pt_enc_get_offset(encoder, &sync[1]); + ptu_int_ge(errcode, 0); + + pt_encode_psb(encoder); + pt_encode_mode_exec(encoder, ptem_64bit); + pt_encode_psbend(encoder); + + errcode = pt_enc_get_offset(encoder, &sync[2]); + ptu_int_ge(errcode, 0); + + pt_encode_psb(encoder); + pt_encode_mode_exec(encoder, ptem_64bit); + pt_encode_psbend(encoder); + + /* Synchronize repeatedly and check that we reach each PSB in the + * correct order. + */ + + errcode = pt_qry_sync_backward(decoder, &ip); + ptu_int_ge(errcode, 0); + + errcode = pt_qry_get_sync_offset(decoder, &offset); + ptu_int_eq(errcode, 0); + ptu_uint_eq(offset, sync[2]); + + errcode = pt_qry_sync_backward(decoder, &ip); + ptu_int_ge(errcode, 0); + + errcode = pt_qry_get_sync_offset(decoder, &offset); + ptu_int_eq(errcode, 0); + ptu_uint_eq(offset, sync[1]); + + errcode = pt_qry_sync_backward(decoder, &ip); + ptu_int_ge(errcode, 0); + + errcode = pt_qry_get_sync_offset(decoder, &offset); + ptu_int_eq(errcode, 0); + ptu_uint_eq(offset, sync[0]); + + errcode = pt_qry_sync_backward(decoder, &ip); + ptu_int_eq(errcode, -pte_eos); + + return ptu_passed(); +} + +static struct ptunit_result +sync_backward_empty_end(struct ptu_decoder_fixture *dfix) +{ + struct pt_query_decoder *decoder = &dfix->decoder; + struct pt_encoder *encoder = &dfix->encoder; + uint64_t sync[3], offset, ip; + int errcode; + + /* Check that we can use repeated pt_qry_sync_backward() to iterate over + * synchronization points in backwards order. + * + * There's an empty PSB+ at the end. We skip it. + */ + + errcode = pt_enc_get_offset(encoder, &sync[0]); + ptu_int_ge(errcode, 0); + + pt_encode_psb(encoder); + pt_encode_mode_exec(encoder, ptem_64bit); + pt_encode_psbend(encoder); + + errcode = pt_enc_get_offset(encoder, &sync[1]); + ptu_int_ge(errcode, 0); + + pt_encode_psb(encoder); + pt_encode_mode_exec(encoder, ptem_64bit); + pt_encode_psbend(encoder); + + errcode = pt_enc_get_offset(encoder, &sync[2]); + ptu_int_ge(errcode, 0); + + pt_encode_psb(encoder); + pt_encode_psbend(encoder); + + /* Synchronize repeatedly and check that we reach each PSB in the + * correct order. + */ + + errcode = pt_qry_sync_backward(decoder, &ip); + ptu_int_ge(errcode, 0); + + errcode = pt_qry_get_sync_offset(decoder, &offset); + ptu_int_eq(errcode, 0); + ptu_uint_eq(offset, sync[1]); + + errcode = pt_qry_sync_backward(decoder, &ip); + ptu_int_ge(errcode, 0); + + errcode = pt_qry_get_sync_offset(decoder, &offset); + ptu_int_eq(errcode, 0); + ptu_uint_eq(offset, sync[0]); + + errcode = pt_qry_sync_backward(decoder, &ip); + ptu_int_eq(errcode, -pte_eos); + + return ptu_passed(); +} + +static struct ptunit_result +sync_backward_empty_mid(struct ptu_decoder_fixture *dfix) +{ + struct pt_query_decoder *decoder = &dfix->decoder; + struct pt_encoder *encoder = &dfix->encoder; + uint64_t sync[3], offset, ip; + int errcode; + + /* Check that we can use repeated pt_qry_sync_backward() to iterate over + * synchronization points in backwards order. + * + * There's an empty PSB+ in the middle. We skip it. + */ + + errcode = pt_enc_get_offset(encoder, &sync[0]); + ptu_int_ge(errcode, 0); + + pt_encode_psb(encoder); + pt_encode_mode_exec(encoder, ptem_64bit); + pt_encode_psbend(encoder); + + errcode = pt_enc_get_offset(encoder, &sync[1]); + ptu_int_ge(errcode, 0); + + pt_encode_psb(encoder); + pt_encode_psbend(encoder); + + errcode = pt_enc_get_offset(encoder, &sync[2]); + ptu_int_ge(errcode, 0); + + pt_encode_psb(encoder); + pt_encode_mode_exec(encoder, ptem_64bit); + pt_encode_psbend(encoder); + + /* Synchronize repeatedly and check that we reach each PSB in the + * correct order. + */ + + errcode = pt_qry_sync_backward(decoder, &ip); + ptu_int_ge(errcode, 0); + + errcode = pt_qry_get_sync_offset(decoder, &offset); + ptu_int_eq(errcode, 0); + ptu_uint_eq(offset, sync[2]); + + errcode = pt_qry_sync_backward(decoder, &ip); + ptu_int_ge(errcode, 0); + + errcode = pt_qry_get_sync_offset(decoder, &offset); + ptu_int_eq(errcode, 0); + ptu_uint_eq(offset, sync[0]); + + errcode = pt_qry_sync_backward(decoder, &ip); + ptu_int_eq(errcode, -pte_eos); + + return ptu_passed(); +} + +static struct ptunit_result +sync_backward_empty_begin(struct ptu_decoder_fixture *dfix) +{ + struct pt_query_decoder *decoder = &dfix->decoder; + struct pt_encoder *encoder = &dfix->encoder; + uint64_t sync[3], offset, ip; + int errcode; + + /* Check that we can use repeated pt_qry_sync_backward() to iterate over + * synchronization points in backwards order. + * + * There's an empty PSB+ at the beginning. We skip it. + */ + + errcode = pt_enc_get_offset(encoder, &sync[0]); + ptu_int_ge(errcode, 0); + + pt_encode_psb(encoder); + pt_encode_psbend(encoder); + + errcode = pt_enc_get_offset(encoder, &sync[1]); + ptu_int_ge(errcode, 0); + + pt_encode_psb(encoder); + pt_encode_mode_exec(encoder, ptem_64bit); + pt_encode_psbend(encoder); + + errcode = pt_enc_get_offset(encoder, &sync[2]); + ptu_int_ge(errcode, 0); + + pt_encode_psb(encoder); + pt_encode_mode_exec(encoder, ptem_64bit); + pt_encode_psbend(encoder); + + /* Synchronize repeatedly and check that we reach each PSB in the + * correct order. + */ + + errcode = pt_qry_sync_backward(decoder, &ip); + ptu_int_ge(errcode, 0); + + errcode = pt_qry_get_sync_offset(decoder, &offset); + ptu_int_eq(errcode, 0); + ptu_uint_eq(offset, sync[2]); + + errcode = pt_qry_sync_backward(decoder, &ip); + ptu_int_ge(errcode, 0); + + errcode = pt_qry_get_sync_offset(decoder, &offset); + ptu_int_eq(errcode, 0); + ptu_uint_eq(offset, sync[1]); + + errcode = pt_qry_sync_backward(decoder, &ip); + ptu_int_eq(errcode, -pte_eos); + + return ptu_passed(); +} + +static struct ptunit_result +decode_sync_backward(struct ptu_decoder_fixture *dfix) +{ + struct pt_query_decoder *decoder = &dfix->decoder; + struct pt_encoder *encoder = &dfix->encoder; + struct pt_event event; + uint64_t sync[2], offset, ip; + int errcode; + + /* Check that we can use sync_backward to re-sync at the current trace + * segment as well as to find the previous trace segment. + */ + + errcode = pt_enc_get_offset(encoder, &sync[0]); + ptu_int_ge(errcode, 0); + + pt_encode_psb(encoder); + pt_encode_mode_exec(encoder, ptem_64bit); + pt_encode_psbend(encoder); + + errcode = pt_enc_get_offset(encoder, &sync[1]); + ptu_int_ge(errcode, 0); + + pt_encode_psb(encoder); + pt_encode_mode_exec(encoder, ptem_64bit); + pt_encode_psbend(encoder); + + + errcode = pt_qry_sync_forward(decoder, &ip); + ptu_int_ge(errcode, 0); + + errcode = pt_qry_get_sync_offset(decoder, &offset); + ptu_int_eq(errcode, 0); + ptu_uint_eq(offset, sync[0]); + + errcode = pt_qry_event(decoder, &event, sizeof(event)); + ptu_int_ge(errcode, 0); + ptu_int_eq(event.type, ptev_exec_mode); + + errcode = pt_qry_event(decoder, &event, sizeof(event)); + ptu_int_ge(errcode, 0); + ptu_int_eq(event.type, ptev_exec_mode); + + errcode = pt_qry_sync_backward(decoder, &ip); + ptu_int_ge(errcode, 0); + + errcode = pt_qry_get_sync_offset(decoder, &offset); + ptu_int_eq(errcode, 0); + ptu_uint_eq(offset, sync[1]); + + errcode = pt_qry_sync_backward(decoder, &ip); + ptu_int_ge(errcode, 0); + + errcode = pt_qry_get_sync_offset(decoder, &offset); + ptu_int_eq(errcode, 0); + ptu_uint_eq(offset, sync[0]); + + errcode = pt_qry_sync_backward(decoder, &ip); + ptu_int_eq(errcode, -pte_eos); + + return ptu_passed(); +} + +static struct ptunit_result indir_null(struct ptu_decoder_fixture *dfix) +{ + struct pt_query_decoder *decoder = &dfix->decoder; + struct pt_config *config = &decoder->config; + uint64_t ip = pt_dfix_bad_ip, addr = ip; + int errcode; + + errcode = pt_qry_indirect_branch(NULL, &addr); + ptu_int_eq(errcode, -pte_invalid); + ptu_uint_eq(addr, ip); + + errcode = pt_qry_indirect_branch(decoder, NULL); + ptu_int_eq(errcode, -pte_invalid); + ptu_ptr_eq(decoder->pos, config->begin); + + return ptu_passed(); +} + +static struct ptunit_result indir_empty(struct ptu_decoder_fixture *dfix) +{ + struct pt_query_decoder *decoder = &dfix->decoder; + struct pt_config *config = &decoder->config; + uint64_t ip = pt_dfix_bad_ip, addr = ip; + int errcode; + + decoder->pos = config->end; + + errcode = pt_qry_indirect_branch(decoder, &addr); + ptu_int_eq(errcode, -pte_eos); + ptu_uint_eq(addr, ip); + + return ptu_passed(); +} + +static struct ptunit_result indir(struct ptu_decoder_fixture *dfix, + enum pt_ip_compression ipc) +{ + struct pt_query_decoder *decoder = &dfix->decoder; + struct pt_encoder *encoder = &dfix->encoder; + struct pt_packet_ip packet; + uint64_t addr = pt_dfix_bad_ip; + int errcode; + + packet.ipc = ipc; + packet.ip = pt_dfix_sext_ip; + pt_last_ip_update_ip(&dfix->last_ip, &packet, &dfix->config); + + pt_encode_tip(encoder, packet.ip, packet.ipc); + + ptu_check(ptu_sync_decoder, decoder); + + errcode = pt_qry_indirect_branch(decoder, &addr); + if (ipc == pt_ipc_suppressed) { + ptu_int_eq(errcode, pts_ip_suppressed | pts_eos); + ptu_uint_eq(addr, pt_dfix_bad_ip); + } else { + ptu_int_eq(errcode, pts_eos); + ptu_uint_eq(addr, dfix->last_ip.ip); + } + + return ptu_passed(); +} + +static struct ptunit_result indir_tnt(struct ptu_decoder_fixture *dfix, + enum pt_ip_compression ipc) +{ + struct pt_query_decoder *decoder = &dfix->decoder; + struct pt_encoder *encoder = &dfix->encoder; + struct pt_packet_ip packet; + uint64_t addr = pt_dfix_bad_ip; + int errcode; + + packet.ipc = ipc; + packet.ip = pt_dfix_sext_ip; + pt_last_ip_update_ip(&dfix->last_ip, &packet, &dfix->config); + + pt_encode_tnt_8(encoder, 0ull, 1); + pt_encode_tip(encoder, packet.ip, packet.ipc); + + ptu_check(ptu_sync_decoder, decoder); + + errcode = pt_qry_indirect_branch(decoder, &addr); + if (ipc == pt_ipc_suppressed) { + ptu_int_eq(errcode, pts_ip_suppressed); + ptu_uint_eq(addr, pt_dfix_bad_ip); + } else { + ptu_int_eq(errcode, 0); + ptu_uint_eq(addr, dfix->last_ip.ip); + } + + return ptu_passed(); +} + +static struct ptunit_result indir_cutoff_fail(struct ptu_decoder_fixture *dfix) +{ + struct pt_query_decoder *decoder = &dfix->decoder; + struct pt_encoder *encoder = &dfix->encoder; + uint64_t ip = pt_dfix_bad_ip, addr = ip; + int errcode; + + pt_encode_tip(encoder, 0, pt_ipc_sext_48); + + ptu_check(cutoff, decoder, encoder); + ptu_check(ptu_sync_decoder, decoder); + + errcode = pt_qry_indirect_branch(decoder, &addr); + ptu_int_eq(errcode, -pte_eos); + ptu_uint_eq(addr, ip); + + return ptu_passed(); +} + +static struct ptunit_result +indir_skip_tnt_fail(struct ptu_decoder_fixture *dfix) +{ + struct pt_query_decoder *decoder = &dfix->decoder; + struct pt_encoder *encoder = &dfix->encoder; + uint64_t ip = pt_dfix_bad_ip, addr = ip; + int errcode; + + pt_encode_tnt_8(encoder, 0, 1); + pt_encode_tnt_8(encoder, 0, 1); + pt_encode_tip(encoder, 0, pt_ipc_sext_48); + + ptu_check(ptu_sync_decoder, decoder); + + errcode = pt_qry_indirect_branch(decoder, &addr); + ptu_int_eq(errcode, -pte_bad_query); + ptu_uint_eq(addr, ip); + + return ptu_passed(); +} + +static struct ptunit_result +indir_skip_tip_pge_fail(struct ptu_decoder_fixture *dfix) +{ + struct pt_query_decoder *decoder = &dfix->decoder; + struct pt_encoder *encoder = &dfix->encoder; + uint64_t ip = pt_dfix_bad_ip, addr = ip; + const uint8_t *pos; + int errcode; + + pos = encoder->pos; + pt_encode_tip_pge(encoder, 0, pt_ipc_sext_48); + pt_encode_tip(encoder, 0, pt_ipc_sext_48); + + ptu_check(ptu_sync_decoder, decoder); + + errcode = pt_qry_indirect_branch(decoder, &addr); + ptu_int_eq(errcode, -pte_bad_query); + ptu_ptr_eq(decoder->pos, pos); + ptu_uint_eq(addr, ip); + + return ptu_passed(); +} + +static struct ptunit_result +indir_skip_tip_pgd_fail(struct ptu_decoder_fixture *dfix) +{ + struct pt_query_decoder *decoder = &dfix->decoder; + struct pt_encoder *encoder = &dfix->encoder; + uint64_t ip = pt_dfix_bad_ip, addr = ip; + const uint8_t *pos; + int errcode; + + pos = encoder->pos; + pt_encode_tip_pgd(encoder, 0, pt_ipc_sext_48); + pt_encode_tip(encoder, 0, pt_ipc_sext_48); + + ptu_check(ptu_sync_decoder, decoder); + + errcode = pt_qry_indirect_branch(decoder, &addr); + ptu_int_eq(errcode, -pte_bad_query); + ptu_ptr_eq(decoder->pos, pos); + ptu_uint_eq(addr, ip); + + return ptu_passed(); +} + +static struct ptunit_result +indir_skip_fup_tip_fail(struct ptu_decoder_fixture *dfix) +{ + struct pt_query_decoder *decoder = &dfix->decoder; + struct pt_encoder *encoder = &dfix->encoder; + uint64_t ip = pt_dfix_bad_ip, addr = ip; + const uint8_t *pos; + int errcode; + + pt_encode_fup(encoder, 0, pt_ipc_sext_48); + pos = encoder->pos; + pt_encode_tip(encoder, 0, pt_ipc_sext_48); + pt_encode_tip(encoder, 0, pt_ipc_sext_48); + + ptu_check(ptu_sync_decoder, decoder); + + errcode = pt_qry_indirect_branch(decoder, &addr); + ptu_int_eq(errcode, -pte_bad_query); + ptu_ptr_eq(decoder->pos, pos); + ptu_uint_eq(addr, ip); + + return ptu_passed(); +} + +static struct ptunit_result +indir_skip_fup_tip_pgd_fail(struct ptu_decoder_fixture *dfix) +{ + struct pt_query_decoder *decoder = &dfix->decoder; + struct pt_encoder *encoder = &dfix->encoder; + uint64_t ip = pt_dfix_bad_ip, addr = ip; + const uint8_t *pos; + int errcode; + + pt_encode_fup(encoder, 0, pt_ipc_sext_48); + pos = encoder->pos; + pt_encode_tip_pgd(encoder, 0, pt_ipc_sext_48); + pt_encode_tip(encoder, 0, pt_ipc_sext_48); + + ptu_check(ptu_sync_decoder, decoder); + + errcode = pt_qry_indirect_branch(decoder, &addr); + ptu_int_eq(errcode, -pte_bad_query); + ptu_ptr_eq(decoder->pos, pos); + ptu_uint_eq(addr, ip); + + return ptu_passed(); +} + +static struct ptunit_result cond_null(struct ptu_decoder_fixture *dfix) +{ + struct pt_query_decoder *decoder = &dfix->decoder; + struct pt_config *config = &decoder->config; + int errcode, tnt = 0xbc, taken = tnt; + + errcode = pt_qry_cond_branch(NULL, &taken); + ptu_int_eq(errcode, -pte_invalid); + ptu_int_eq(taken, tnt); + + errcode = pt_qry_cond_branch(decoder, NULL); + ptu_int_eq(errcode, -pte_invalid); + ptu_ptr_eq(decoder->pos, config->begin); + + return ptu_passed(); +} + +static struct ptunit_result cond_empty(struct ptu_decoder_fixture *dfix) +{ + struct pt_query_decoder *decoder = &dfix->decoder; + struct pt_config *config = &decoder->config; + int errcode, tnt = 0xbc, taken = tnt; + + decoder->pos = config->end; + + errcode = pt_qry_cond_branch(decoder, &taken); + ptu_int_eq(errcode, -pte_eos); + ptu_int_eq(taken, tnt); + + return ptu_passed(); +} + +static struct ptunit_result cond(struct ptu_decoder_fixture *dfix) +{ + struct pt_query_decoder *decoder = &dfix->decoder; + struct pt_encoder *encoder = &dfix->encoder; + int errcode, tnt = 0xbc, taken = tnt; + + pt_encode_tnt_8(encoder, 0x02, 3); + + ptu_check(ptu_sync_decoder, decoder); + + errcode = pt_qry_cond_branch(decoder, &taken); + ptu_int_eq(errcode, 0); + ptu_int_eq(taken, 0); + + taken = tnt; + errcode = pt_qry_cond_branch(decoder, &taken); + ptu_int_eq(errcode, 0); + ptu_int_eq(taken, 1); + + taken = tnt; + errcode = pt_qry_cond_branch(decoder, &taken); + ptu_int_eq(errcode, pts_eos); + ptu_int_eq(taken, 0); + + taken = tnt; + errcode = pt_qry_cond_branch(decoder, &taken); + ptu_int_eq(errcode, -pte_eos); + ptu_int_eq(taken, tnt); + + return ptu_passed(); +} + +static struct ptunit_result cond_skip_tip_fail(struct ptu_decoder_fixture *dfix) +{ + struct pt_query_decoder *decoder = &dfix->decoder; + struct pt_encoder *encoder = &dfix->encoder; + int errcode, tnt = 0xbc, taken = tnt; + const uint8_t *pos; + + pos = encoder->pos; + pt_encode_tip(encoder, 0, pt_ipc_sext_48); + pt_encode_tnt_8(encoder, 0, 1); + + ptu_check(ptu_sync_decoder, decoder); + + errcode = pt_qry_cond_branch(decoder, &taken); + ptu_int_eq(errcode, -pte_bad_query); + ptu_ptr_eq(decoder->pos, pos); + ptu_int_eq(taken, tnt); + + return ptu_passed(); +} + +static struct ptunit_result +cond_skip_tip_pge_fail(struct ptu_decoder_fixture *dfix) +{ + struct pt_query_decoder *decoder = &dfix->decoder; + struct pt_encoder *encoder = &dfix->encoder; + int errcode, tnt = 0xbc, taken = tnt; + const uint8_t *pos; + + pos = encoder->pos; + pt_encode_tip_pge(encoder, 0, pt_ipc_sext_48); + pt_encode_tnt_8(encoder, 0, 1); + + ptu_check(ptu_sync_decoder, decoder); + + errcode = pt_qry_cond_branch(decoder, &taken); + ptu_int_eq(errcode, -pte_bad_query); + ptu_ptr_eq(decoder->pos, pos); + ptu_int_eq(taken, tnt); + + return ptu_passed(); +} + +static struct ptunit_result +cond_skip_tip_pgd_fail(struct ptu_decoder_fixture *dfix) +{ + struct pt_query_decoder *decoder = &dfix->decoder; + struct pt_encoder *encoder = &dfix->encoder; + int errcode, tnt = 0xbc, taken = tnt; + const uint8_t *pos; + + pos = encoder->pos; + pt_encode_tip_pgd(encoder, 0, pt_ipc_sext_48); + pt_encode_tnt_8(encoder, 0, 1); + + ptu_check(ptu_sync_decoder, decoder); + + errcode = pt_qry_cond_branch(decoder, &taken); + ptu_int_eq(errcode, -pte_bad_query); + ptu_ptr_eq(decoder->pos, pos); + ptu_int_eq(taken, tnt); + + return ptu_passed(); +} + +static struct ptunit_result +cond_skip_fup_tip_fail(struct ptu_decoder_fixture *dfix) +{ + struct pt_query_decoder *decoder = &dfix->decoder; + struct pt_encoder *encoder = &dfix->encoder; + int errcode, tnt = 0xbc, taken = tnt; + const uint8_t *pos; + + pt_encode_fup(encoder, 0, pt_ipc_sext_48); + pos = encoder->pos; + pt_encode_tip(encoder, 0, pt_ipc_sext_48); + pt_encode_tnt_8(encoder, 0, 1); + + ptu_check(ptu_sync_decoder, decoder); + + errcode = pt_qry_cond_branch(decoder, &taken); + ptu_int_eq(errcode, -pte_bad_query); + ptu_ptr_eq(decoder->pos, pos); + ptu_int_eq(taken, tnt); + + return ptu_passed(); +} + +static struct ptunit_result +cond_skip_fup_tip_pgd_fail(struct ptu_decoder_fixture *dfix) +{ + struct pt_query_decoder *decoder = &dfix->decoder; + struct pt_encoder *encoder = &dfix->encoder; + int errcode, tnt = 0xbc, taken = tnt; + const uint8_t *pos; + + pt_encode_fup(encoder, 0, pt_ipc_sext_48); + pos = encoder->pos; + pt_encode_tip_pgd(encoder, 0, pt_ipc_sext_48); + pt_encode_tnt_8(encoder, 0, 1); + + ptu_check(ptu_sync_decoder, decoder); + + errcode = pt_qry_cond_branch(decoder, &taken); + ptu_int_eq(errcode, -pte_bad_query); + ptu_ptr_eq(decoder->pos, pos); + ptu_int_eq(taken, tnt); + + return ptu_passed(); +} + +static struct ptunit_result event_null(struct ptu_decoder_fixture *dfix) +{ + struct pt_query_decoder *decoder = &dfix->decoder; + struct pt_config *config = &decoder->config; + struct pt_event event; + int errcode; + + errcode = pt_qry_event(NULL, &event, sizeof(event)); + ptu_int_eq(errcode, -pte_invalid); + + errcode = pt_qry_event(decoder, NULL, sizeof(event)); + ptu_int_eq(errcode, -pte_invalid); + ptu_ptr_eq(decoder->pos, config->begin); + + return ptu_passed(); +} + +static struct ptunit_result event_bad_size(struct ptu_decoder_fixture *dfix) +{ + struct pt_query_decoder *decoder = &dfix->decoder; + struct pt_event event; + int errcode; + + errcode = pt_qry_event(decoder, &event, 4); + ptu_int_eq(errcode, -pte_invalid); + + return ptu_passed(); +} + +static struct ptunit_result event_small_size(struct ptu_decoder_fixture *dfix) +{ + struct pt_query_decoder *decoder = &dfix->decoder; + struct pt_encoder *encoder = &dfix->encoder; + union { + struct pt_event event; + uint8_t buffer[41]; + } variant; + int errcode; + + memset(variant.buffer, 0xcd, sizeof(variant.buffer)); + + pt_encode_tip_pge(encoder, 0ull, pt_ipc_sext_48); + + ptu_check(ptu_sync_decoder, decoder); + + errcode = pt_qry_event(decoder, &variant.event, 40); + ptu_int_eq(errcode, pts_eos); + ptu_int_eq(variant.event.type, ptev_enabled); + ptu_uint_eq(variant.buffer[40], 0xcd); + + return ptu_passed(); +} + +static struct ptunit_result event_big_size(struct ptu_decoder_fixture *dfix) +{ + struct pt_query_decoder *decoder = &dfix->decoder; + struct pt_encoder *encoder = &dfix->encoder; + union { + struct pt_event event; + uint8_t buffer[1024]; + } variant; + int errcode; + + memset(variant.buffer, 0xcd, sizeof(variant.buffer)); + + pt_encode_tip_pge(encoder, 0ull, pt_ipc_sext_48); + + ptu_check(ptu_sync_decoder, decoder); + + errcode = pt_qry_event(decoder, &variant.event, sizeof(variant.buffer)); + ptu_int_eq(errcode, pts_eos); + ptu_int_eq(variant.event.type, ptev_enabled); + ptu_uint_eq(variant.buffer[sizeof(variant.event)], 0xcd); + + return ptu_passed(); +} + +static struct ptunit_result event_empty(struct ptu_decoder_fixture *dfix) +{ + struct pt_query_decoder *decoder = &dfix->decoder; + struct pt_config *config = &decoder->config; + struct pt_event event; + int errcode; + + decoder->pos = config->end; + + errcode = pt_qry_event(decoder, &event, sizeof(event)); + ptu_int_eq(errcode, -pte_eos); + + return ptu_passed(); +} + +static struct ptunit_result event_enabled(struct ptu_decoder_fixture *dfix, + enum pt_ip_compression ipc, + uint64_t tsc) +{ + struct pt_query_decoder *decoder = &dfix->decoder; + struct pt_encoder *encoder = &dfix->encoder; + struct pt_packet_ip packet; + struct pt_event event; + int errcode; + + packet.ipc = ipc; + packet.ip = pt_dfix_max_ip; + pt_last_ip_update_ip(&dfix->last_ip, &packet, &dfix->config); + + pt_encode_tip_pge(encoder, packet.ip, packet.ipc); + + ptu_check(ptu_sync_decoder, decoder); + + errcode = pt_qry_event(decoder, &event, sizeof(event)); + if (ipc == pt_ipc_suppressed) + ptu_int_eq(errcode, -pte_bad_packet); + else { + ptu_int_eq(errcode, pts_eos); + ptu_int_eq(event.type, ptev_enabled); + ptu_uint_eq(event.variant.enabled.ip, dfix->last_ip.ip); + + if (!tsc) + ptu_int_eq(event.has_tsc, 0); + else { + ptu_int_eq(event.has_tsc, 1); + ptu_uint_eq(event.tsc, tsc); + } + } + + return ptu_passed(); +} + +static struct ptunit_result +event_enabled_cutoff_fail(struct ptu_decoder_fixture *dfix) +{ + struct pt_query_decoder *decoder = &dfix->decoder; + struct pt_encoder *encoder = &dfix->encoder; + struct pt_event event; + int errcode; + + pt_encode_tip_pge(encoder, 0, pt_ipc_sext_48); + + ptu_check(cutoff, decoder, encoder); + ptu_check(ptu_sync_decoder, decoder); + + errcode = pt_qry_event(decoder, &event, sizeof(event)); + ptu_int_eq(errcode, -pte_eos); + + return ptu_passed(); +} + +static struct ptunit_result event_disabled(struct ptu_decoder_fixture *dfix, + enum pt_ip_compression ipc, + uint64_t tsc) +{ + struct pt_query_decoder *decoder = &dfix->decoder; + struct pt_encoder *encoder = &dfix->encoder; + struct pt_packet_ip packet; + struct pt_event event; + int errcode; + + packet.ipc = ipc; + packet.ip = pt_dfix_sext_ip; + pt_last_ip_update_ip(&dfix->last_ip, &packet, &dfix->config); + + pt_encode_tip_pgd(encoder, packet.ip, packet.ipc); + + ptu_check(ptu_sync_decoder, decoder); + + errcode = pt_qry_event(decoder, &event, sizeof(event)); + ptu_int_eq(errcode, pts_eos); + if (ipc == pt_ipc_suppressed) + ptu_uint_ne(event.ip_suppressed, 0); + else { + ptu_uint_eq(event.ip_suppressed, 0); + ptu_uint_eq(event.variant.disabled.ip, dfix->last_ip.ip); + } + ptu_int_eq(event.type, ptev_disabled); + + if (!tsc) + ptu_int_eq(event.has_tsc, 0); + else { + ptu_int_eq(event.has_tsc, 1); + ptu_uint_eq(event.tsc, tsc); + } + + return ptu_passed(); +} + +static struct ptunit_result +event_disabled_cutoff_fail(struct ptu_decoder_fixture *dfix) +{ + struct pt_query_decoder *decoder = &dfix->decoder; + struct pt_encoder *encoder = &dfix->encoder; + struct pt_event event; + int errcode; + + pt_encode_tip_pgd(encoder, 0, pt_ipc_update_32); + + ptu_check(cutoff, decoder, encoder); + ptu_check(ptu_sync_decoder, decoder); + + errcode = pt_qry_event(decoder, &event, sizeof(event)); + ptu_int_eq(errcode, -pte_eos); + + return ptu_passed(); +} + +static struct ptunit_result +event_async_disabled(struct ptu_decoder_fixture *dfix, + enum pt_ip_compression ipc, uint64_t tsc) +{ + struct pt_query_decoder *decoder = &dfix->decoder; + struct pt_encoder *encoder = &dfix->encoder; + struct pt_packet_ip fup, tip; + struct pt_event event; + int errcode; + + fup.ipc = pt_ipc_sext_48; + fup.ip = pt_dfix_max_ip; + pt_last_ip_update_ip(&dfix->last_ip, &fup, &dfix->config); + + tip.ipc = ipc; + tip.ip = pt_dfix_sext_ip; + pt_last_ip_update_ip(&dfix->last_ip, &tip, &dfix->config); + + pt_encode_fup(encoder, fup.ip, fup.ipc); + pt_encode_tip_pgd(encoder, tip.ip, tip.ipc); + + ptu_check(ptu_sync_decoder, decoder); + + errcode = pt_qry_event(decoder, &event, sizeof(event)); + ptu_int_eq(errcode, pts_eos); + if (ipc == pt_ipc_suppressed) + ptu_uint_ne(event.ip_suppressed, 0); + else { + ptu_uint_eq(event.ip_suppressed, 0); + ptu_uint_eq(event.variant.async_disabled.ip, dfix->last_ip.ip); + } + ptu_int_eq(event.type, ptev_async_disabled); + ptu_uint_eq(event.variant.async_disabled.at, fup.ip); + + if (!tsc) + ptu_int_eq(event.has_tsc, 0); + else { + ptu_int_eq(event.has_tsc, 1); + ptu_uint_eq(event.tsc, tsc); + } + + return ptu_passed(); +} + +static struct ptunit_result +event_async_disabled_suppressed_fail(struct ptu_decoder_fixture *dfix) +{ + struct pt_query_decoder *decoder = &dfix->decoder; + struct pt_encoder *encoder = &dfix->encoder; + struct pt_event event; + int errcode; + + pt_encode_fup(encoder, 0, pt_ipc_suppressed); + pt_encode_tip_pgd(encoder, 0, pt_ipc_sext_48); + + ptu_check(ptu_sync_decoder, decoder); + + errcode = pt_qry_event(decoder, &event, sizeof(event)); + ptu_int_eq(errcode, -pte_ip_suppressed); + + return ptu_passed(); +} + +static struct ptunit_result +event_async_disabled_cutoff_fail_a(struct ptu_decoder_fixture *dfix) +{ + struct pt_query_decoder *decoder = &dfix->decoder; + struct pt_encoder *encoder = &dfix->encoder; + struct pt_event event; + uint64_t at = pt_dfix_sext_ip; + int errcode; + + pt_encode_fup(encoder, at, pt_ipc_sext_48); + pt_encode_tip_pgd(encoder, 0, pt_ipc_update_16); + + ptu_check(cutoff, decoder, encoder); + ptu_check(ptu_sync_decoder, decoder); + + errcode = pt_qry_event(decoder, &event, sizeof(event)); + ptu_int_eq(errcode, -pte_eos); + + return ptu_passed(); +} + +static struct ptunit_result +event_async_disabled_cutoff_fail_b(struct ptu_decoder_fixture *dfix) +{ + struct pt_query_decoder *decoder = &dfix->decoder; + struct pt_encoder *encoder = &dfix->encoder; + struct pt_event event; + int errcode; + + pt_encode_fup(encoder, 0, pt_ipc_sext_48); + + ptu_check(cutoff, decoder, encoder); + ptu_check(ptu_sync_decoder, decoder); + + errcode = pt_qry_event(decoder, &event, sizeof(event)); + ptu_int_eq(errcode, -pte_eos); + + return ptu_passed(); +} + +static struct ptunit_result +event_async_branch_suppressed_fail(struct ptu_decoder_fixture *dfix) +{ + struct pt_query_decoder *decoder = &dfix->decoder; + struct pt_encoder *encoder = &dfix->encoder; + struct pt_event event; + int errcode; + + pt_encode_fup(encoder, 0, pt_ipc_suppressed); + + ptu_check(ptu_sync_decoder, decoder); + + errcode = pt_qry_event(decoder, &event, sizeof(event)); + ptu_int_eq(errcode, -pte_ip_suppressed); + + return ptu_passed(); +} + +static struct ptunit_result event_async_branch(struct ptu_decoder_fixture *dfix, + enum pt_ip_compression ipc, + uint64_t tsc) +{ + struct pt_query_decoder *decoder = &dfix->decoder; + struct pt_encoder *encoder = &dfix->encoder; + struct pt_packet_ip fup, tip; + struct pt_event event; + int errcode; + + fup.ipc = pt_ipc_sext_48; + fup.ip = pt_dfix_max_ip; + pt_last_ip_update_ip(&dfix->last_ip, &fup, &dfix->config); + + tip.ipc = ipc; + tip.ip = pt_dfix_sext_ip; + pt_last_ip_update_ip(&dfix->last_ip, &tip, &dfix->config); + + pt_encode_fup(encoder, fup.ip, fup.ipc); + pt_encode_tip(encoder, tip.ip, tip.ipc); + + ptu_check(ptu_sync_decoder, decoder); + + errcode = pt_qry_event(decoder, &event, sizeof(event)); + ptu_int_eq(errcode, pts_eos); + if (ipc == pt_ipc_suppressed) + ptu_uint_ne(event.ip_suppressed, 0); + else { + ptu_uint_eq(event.ip_suppressed, 0); + ptu_uint_eq(event.variant.async_branch.to, dfix->last_ip.ip); + } + ptu_int_eq(event.type, ptev_async_branch); + ptu_uint_eq(event.variant.async_branch.from, fup.ip); + + if (!tsc) + ptu_int_eq(event.has_tsc, 0); + else { + ptu_int_eq(event.has_tsc, 1); + ptu_uint_eq(event.tsc, tsc); + } + + return ptu_passed(); +} + +static struct ptunit_result +event_async_branch_cutoff_fail_a(struct ptu_decoder_fixture *dfix) +{ + struct pt_query_decoder *decoder = &dfix->decoder; + struct pt_encoder *encoder = &dfix->encoder; + struct pt_event event; + int errcode; + + pt_encode_fup(encoder, 0, pt_ipc_sext_48); + pt_encode_tip_pgd(encoder, 0, pt_ipc_update_16); + + ptu_check(cutoff, decoder, encoder); + ptu_check(ptu_sync_decoder, decoder); + + errcode = pt_qry_event(decoder, &event, sizeof(event)); + ptu_int_eq(errcode, -pte_eos); + + return ptu_passed(); +} + +static struct ptunit_result +event_async_branch_cutoff_fail_b(struct ptu_decoder_fixture *dfix) +{ + struct pt_query_decoder *decoder = &dfix->decoder; + struct pt_encoder *encoder = &dfix->encoder; + struct pt_event event; + int errcode; + + pt_encode_fup(encoder, 0, pt_ipc_sext_48); + + ptu_check(cutoff, decoder, encoder); + ptu_check(ptu_sync_decoder, decoder); + + errcode = pt_qry_event(decoder, &event, sizeof(event)); + ptu_int_eq(errcode, -pte_eos); + + return ptu_passed(); +} + +static struct ptunit_result event_paging(struct ptu_decoder_fixture *dfix, + uint8_t flags, uint64_t tsc) +{ + struct pt_query_decoder *decoder = &dfix->decoder; + struct pt_encoder *encoder = &dfix->encoder; + struct pt_event event; + uint64_t cr3 = pt_dfix_max_cr3; + int errcode; + + pt_encode_pip(encoder, cr3, flags); + + ptu_check(ptu_sync_decoder, decoder); + + errcode = pt_qry_event(decoder, &event, sizeof(event)); + ptu_int_eq(errcode, pts_eos); + ptu_int_eq(event.type, ptev_paging); + ptu_uint_eq(event.variant.paging.cr3, cr3); + ptu_uint_eq(event.variant.paging.non_root, (flags & pt_pl_pip_nr) != 0); + + if (!tsc) + ptu_int_eq(event.has_tsc, 0); + else { + ptu_int_eq(event.has_tsc, 1); + ptu_uint_eq(event.tsc, tsc); + } + + return ptu_passed(); +} + +static struct ptunit_result +event_paging_cutoff_fail(struct ptu_decoder_fixture *dfix) +{ + struct pt_query_decoder *decoder = &dfix->decoder; + struct pt_encoder *encoder = &dfix->encoder; + struct pt_event event; + int errcode; + + pt_encode_pip(encoder, 0, 0); + + ptu_check(cutoff, decoder, encoder); + ptu_check(ptu_sync_decoder, decoder); + + errcode = pt_qry_event(decoder, &event, sizeof(event)); + ptu_int_eq(errcode, -pte_eos); + + return ptu_passed(); +} + +static struct ptunit_result +event_async_paging(struct ptu_decoder_fixture *dfix, uint8_t flags, + uint64_t tsc) +{ + struct pt_query_decoder *decoder = &dfix->decoder; + struct pt_encoder *encoder = &dfix->encoder; + struct pt_event event; + uint64_t to = pt_dfix_sext_ip, from = to & ~0xffffull; + uint64_t cr3 = pt_dfix_max_cr3; + int errcode; + + pt_encode_fup(encoder, from, pt_ipc_sext_48); + pt_encode_pip(encoder, cr3, flags); + pt_encode_tip(encoder, to, pt_ipc_update_16); + + ptu_check(ptu_sync_decoder, decoder); + + errcode = pt_qry_event(decoder, &event, sizeof(event)); + ptu_int_eq(errcode, pts_event_pending); + ptu_int_eq(event.type, ptev_async_branch); + ptu_uint_eq(event.variant.async_branch.from, from); + ptu_uint_eq(event.variant.async_branch.to, to); + + if (!tsc) + ptu_int_eq(event.has_tsc, 0); + else { + ptu_int_eq(event.has_tsc, 1); + ptu_uint_eq(event.tsc, tsc); + } + + errcode = pt_qry_event(decoder, &event, sizeof(event)); + ptu_int_eq(errcode, pts_eos); + ptu_int_eq(event.type, ptev_async_paging); + ptu_uint_eq(event.variant.async_paging.cr3, cr3); + ptu_uint_eq(event.variant.async_paging.non_root, + (flags & pt_pl_pip_nr) != 0); + ptu_uint_eq(event.variant.async_paging.ip, to); + + if (!tsc) + ptu_int_eq(event.has_tsc, 0); + else { + ptu_int_eq(event.has_tsc, 1); + ptu_uint_eq(event.tsc, tsc); + } + + return ptu_passed(); +} + +static struct ptunit_result +event_async_paging_suppressed(struct ptu_decoder_fixture *dfix, uint8_t flags, + uint64_t tsc) +{ + struct pt_query_decoder *decoder = &dfix->decoder; + struct pt_encoder *encoder = &dfix->encoder; + struct pt_event event; + uint64_t from = pt_dfix_sext_ip, cr3 = pt_dfix_max_cr3; + int errcode; + + pt_encode_fup(encoder, from, pt_ipc_sext_48); + pt_encode_pip(encoder, cr3, flags); + pt_encode_tip(encoder, 0, pt_ipc_suppressed); + + ptu_check(ptu_sync_decoder, decoder); + + errcode = pt_qry_event(decoder, &event, sizeof(event)); + ptu_int_eq(errcode, pts_event_pending); + ptu_uint_ne(event.ip_suppressed, 0); + ptu_int_eq(event.type, ptev_async_branch); + ptu_uint_eq(event.variant.async_branch.from, from); + + if (!tsc) + ptu_int_eq(event.has_tsc, 0); + else { + ptu_int_eq(event.has_tsc, 1); + ptu_uint_eq(event.tsc, tsc); + } + + errcode = pt_qry_event(decoder, &event, sizeof(event)); + ptu_int_eq(errcode, pts_eos); + ptu_uint_ne(event.ip_suppressed, 0); + ptu_int_eq(event.type, ptev_async_paging); + ptu_uint_eq(event.variant.async_paging.cr3, cr3); + ptu_uint_eq(event.variant.async_paging.non_root, + (flags & pt_pl_pip_nr) != 0); + + if (!tsc) + ptu_int_eq(event.has_tsc, 0); + else { + ptu_int_eq(event.has_tsc, 1); + ptu_uint_eq(event.tsc, tsc); + } + + return ptu_passed(); +} + +static struct ptunit_result +event_async_paging_cutoff_fail(struct ptu_decoder_fixture *dfix) +{ + struct pt_query_decoder *decoder = &dfix->decoder; + struct pt_encoder *encoder = &dfix->encoder; + struct pt_event event; + int errcode; + + pt_encode_fup(encoder, 0, pt_ipc_sext_48); + pt_encode_pip(encoder, 0, 0); + + ptu_check(cutoff, decoder, encoder); + ptu_check(ptu_sync_decoder, decoder); + + errcode = pt_qry_event(decoder, &event, sizeof(event)); + ptu_int_eq(errcode, -pte_eos); + + return ptu_passed(); +} + +static struct ptunit_result event_overflow_fup(struct ptu_decoder_fixture *dfix, + enum pt_ip_compression ipc, + uint64_t tsc) +{ + struct pt_query_decoder *decoder = &dfix->decoder; + struct pt_encoder *encoder = &dfix->encoder; + struct pt_event event; + struct pt_packet_ip packet; + int errcode; + + packet.ipc = ipc; + packet.ip = 0xccull; + + pt_last_ip_init(&dfix->last_ip); + pt_last_ip_update_ip(&dfix->last_ip, &packet, &dfix->config); + + pt_encode_ovf(encoder); + pt_encode_fup(encoder, packet.ip, packet.ipc); + + ptu_check(ptu_sync_decoder, decoder); + + errcode = pt_qry_event(decoder, &event, sizeof(event)); + switch (ipc) { + case pt_ipc_suppressed: + ptu_int_eq(errcode, -pte_noip); + break; + + case pt_ipc_update_16: + case pt_ipc_update_32: + case pt_ipc_update_48: + case pt_ipc_sext_48: + case pt_ipc_full: + ptu_int_eq(errcode, pts_eos); + ptu_int_eq(event.type, ptev_overflow); + ptu_uint_eq(event.variant.overflow.ip, dfix->last_ip.ip); + + if (!tsc) + ptu_int_eq(event.has_tsc, 0); + else { + ptu_int_eq(event.has_tsc, 1); + ptu_uint_eq(event.tsc, tsc); + } + break; + } + + return ptu_passed(); +} + +static struct ptunit_result +event_overflow_tip_pge(struct ptu_decoder_fixture *dfix, + enum pt_ip_compression ipc, uint64_t tsc) +{ + struct pt_query_decoder *decoder = &dfix->decoder; + struct pt_encoder *encoder = &dfix->encoder; + struct pt_event event; + struct pt_packet_ip packet; + int errcode; + + packet.ipc = ipc; + packet.ip = 0xccull; + + pt_last_ip_init(&dfix->last_ip); + pt_last_ip_update_ip(&dfix->last_ip, &packet, &dfix->config); + + pt_encode_ovf(encoder); + pt_encode_tip_pge(encoder, packet.ip, packet.ipc); + + ptu_check(ptu_sync_decoder, decoder); + + errcode = pt_qry_event(decoder, &event, sizeof(event)); + ptu_int_eq(errcode, pts_event_pending); + ptu_int_eq(event.type, ptev_overflow); + ptu_uint_ne(event.ip_suppressed, 0); + + if (!tsc) + ptu_int_eq(event.has_tsc, 0); + else { + ptu_int_eq(event.has_tsc, 1); + ptu_uint_eq(event.tsc, tsc); + } + + errcode = pt_qry_event(decoder, &event, sizeof(event)); + switch (ipc) { + case pt_ipc_suppressed: + ptu_int_eq(errcode, -pte_bad_packet); + break; + + case pt_ipc_update_16: + case pt_ipc_update_32: + case pt_ipc_update_48: + case pt_ipc_sext_48: + case pt_ipc_full: + ptu_int_eq(errcode, pts_eos); + ptu_int_eq(event.type, ptev_enabled); + ptu_uint_eq(event.variant.enabled.ip, dfix->last_ip.ip); + + if (!tsc) + ptu_int_eq(event.has_tsc, 0); + else { + ptu_int_eq(event.has_tsc, 1); + ptu_uint_eq(event.tsc, tsc); + } + break; + } + + return ptu_passed(); +} + +static struct ptunit_result +event_overflow_cutoff_fail(struct ptu_decoder_fixture *dfix) +{ + struct pt_query_decoder *decoder = &dfix->decoder; + struct pt_encoder *encoder = &dfix->encoder; + struct pt_event event; + int errcode; + + pt_encode_ovf(encoder); + + ptu_check(cutoff, decoder, encoder); + ptu_check(ptu_sync_decoder, decoder); + + errcode = pt_qry_event(decoder, &event, sizeof(event)); + ptu_int_eq(errcode, -pte_eos); + + return ptu_passed(); +} + +static struct ptunit_result event_stop(struct ptu_decoder_fixture *dfix, + uint64_t tsc) +{ + struct pt_query_decoder *decoder = &dfix->decoder; + struct pt_encoder *encoder = &dfix->encoder; + struct pt_event event; + int errcode; + + pt_encode_stop(encoder); + + ptu_sync_decoder(decoder); + + errcode = pt_qry_event(decoder, &event, sizeof(event)); + ptu_int_eq(errcode, pts_eos); + ptu_int_eq(event.type, ptev_stop); + + if (!tsc) + ptu_int_eq(event.has_tsc, 0); + else { + ptu_int_eq(event.has_tsc, 1); + ptu_uint_eq(event.tsc, tsc); + } + + return ptu_passed(); +} + +static struct ptunit_result +event_exec_mode_tip(struct ptu_decoder_fixture *dfix, + enum pt_ip_compression ipc, uint64_t tsc) +{ + struct pt_query_decoder *decoder = &dfix->decoder; + struct pt_encoder *encoder = &dfix->encoder; + enum pt_exec_mode mode = ptem_16bit; + struct pt_packet_ip packet; + struct pt_event event; + uint64_t addr = 0ull; + int errcode; + + packet.ipc = ipc; + packet.ip = pt_dfix_max_ip; + pt_last_ip_update_ip(&dfix->last_ip, &packet, &dfix->config); + + pt_encode_mode_exec(encoder, mode); + pt_encode_tip(encoder, packet.ip, packet.ipc); + + ptu_check(ptu_sync_decoder, decoder); + + errcode = pt_qry_event(decoder, &event, sizeof(event)); + ptu_int_eq(errcode, 0); + if (ipc == pt_ipc_suppressed) + ptu_uint_ne(event.ip_suppressed, 0); + else { + ptu_uint_eq(event.ip_suppressed, 0); + ptu_uint_eq(event.variant.exec_mode.ip, dfix->last_ip.ip); + } + ptu_int_eq(event.type, ptev_exec_mode); + ptu_int_eq(event.variant.exec_mode.mode, mode); + + if (!tsc) + ptu_int_eq(event.has_tsc, 0); + else { + ptu_int_eq(event.has_tsc, 1); + ptu_uint_eq(event.tsc, tsc); + } + + errcode = pt_qry_indirect_branch(decoder, &addr); + if (ipc == pt_ipc_suppressed) + ptu_int_eq(errcode, pts_ip_suppressed | pts_eos); + else { + ptu_int_eq(errcode, pts_eos); + ptu_uint_eq(addr, dfix->last_ip.ip); + } + + return ptu_passed(); +} + +static struct ptunit_result +event_exec_mode_tip_cutoff_fail(struct ptu_decoder_fixture *dfix) +{ + struct pt_query_decoder *decoder = &dfix->decoder; + struct pt_encoder *encoder = &dfix->encoder; + struct pt_event event; + int errcode; + + pt_encode_mode_exec(encoder, ptem_32bit); + pt_encode_tip(encoder, 0, pt_ipc_update_16); + + ptu_check(cutoff, decoder, encoder); + ptu_check(ptu_sync_decoder, decoder); + + errcode = pt_qry_event(decoder, &event, sizeof(event)); + ptu_int_eq(errcode, -pte_eos); + + return ptu_passed(); +} + +static struct ptunit_result +event_exec_mode_tip_pge(struct ptu_decoder_fixture *dfix, + enum pt_ip_compression ipc, uint64_t tsc) +{ + struct pt_query_decoder *decoder = &dfix->decoder; + struct pt_encoder *encoder = &dfix->encoder; + enum pt_exec_mode mode = ptem_16bit; + struct pt_packet_ip packet; + struct pt_event event; + uint64_t addr = 0ull; + int errcode; + + packet.ipc = ipc; + packet.ip = pt_dfix_max_ip; + pt_last_ip_update_ip(&dfix->last_ip, &packet, &dfix->config); + + pt_encode_mode_exec(encoder, mode); + pt_encode_tip_pge(encoder, packet.ip, packet.ipc); + + ptu_check(ptu_sync_decoder, decoder); + decoder->enabled = 0; + + errcode = pt_qry_event(decoder, &event, sizeof(event)); + if (ipc == pt_ipc_suppressed) { + ptu_int_eq(errcode, -pte_bad_packet); + ptu_uint_eq(addr, 0ull); + } else { + ptu_int_eq(errcode, pts_event_pending); + ptu_int_eq(event.type, ptev_enabled); + ptu_uint_eq(event.variant.enabled.ip, dfix->last_ip.ip); + + if (!tsc) + ptu_int_eq(event.has_tsc, 0); + else { + ptu_int_eq(event.has_tsc, 1); + ptu_uint_eq(event.tsc, tsc); + } + + errcode = pt_qry_event(decoder, &event, sizeof(event)); + ptu_int_eq(errcode, pts_eos); + ptu_int_eq(event.type, ptev_exec_mode); + ptu_int_eq(event.variant.exec_mode.mode, mode); + ptu_uint_eq(event.variant.exec_mode.ip, dfix->last_ip.ip); + + if (!tsc) + ptu_int_eq(event.has_tsc, 0); + else { + ptu_int_eq(event.has_tsc, 1); + ptu_uint_eq(event.tsc, tsc); + } + } + + return ptu_passed(); +} + +static struct ptunit_result +event_exec_mode_tip_pge_cutoff_fail(struct ptu_decoder_fixture *dfix) +{ + struct pt_query_decoder *decoder = &dfix->decoder; + struct pt_encoder *encoder = &dfix->encoder; + struct pt_event event; + int errcode; + + pt_encode_mode_exec(encoder, ptem_16bit); + pt_encode_tip_pge(encoder, 0, pt_ipc_sext_48); + + ptu_check(cutoff, decoder, encoder); + ptu_check(ptu_sync_decoder, decoder); + + errcode = pt_qry_event(decoder, &event, sizeof(event)); + ptu_int_eq(errcode, -pte_eos); + + return ptu_passed(); +} + +static struct ptunit_result +event_exec_mode_cutoff_fail(struct ptu_decoder_fixture *dfix) +{ + struct pt_query_decoder *decoder = &dfix->decoder; + struct pt_encoder *encoder = &dfix->encoder; + struct pt_event event; + int errcode; + + pt_encode_mode_exec(encoder, ptem_64bit); + + ptu_check(cutoff, decoder, encoder); + ptu_check(ptu_sync_decoder, decoder); + + errcode = pt_qry_event(decoder, &event, sizeof(event)); + ptu_int_eq(errcode, -pte_eos); + + return ptu_passed(); +} + +static struct ptunit_result event_tsx_fup(struct ptu_decoder_fixture *dfix, + enum pt_ip_compression ipc, + uint8_t flags, uint64_t tsc) +{ + struct pt_query_decoder *decoder = &dfix->decoder; + struct pt_encoder *encoder = &dfix->encoder; + struct pt_packet_ip fup, tip; + struct pt_event event; + uint64_t addr = 0; + int errcode; + + fup.ipc = ipc; + fup.ip = pt_dfix_max_ip; + pt_last_ip_update_ip(&dfix->last_ip, &fup, &dfix->config); + + tip.ipc = pt_ipc_sext_48; + tip.ip = pt_dfix_sext_ip; + + pt_encode_mode_tsx(encoder, flags); + pt_encode_fup(encoder, fup.ip, fup.ipc); + pt_encode_tip(encoder, tip.ip, tip.ipc); + + ptu_check(ptu_sync_decoder, decoder); + + errcode = pt_qry_event(decoder, &event, sizeof(event)); + ptu_int_eq(errcode, 0); + if (ipc == pt_ipc_suppressed) + ptu_uint_ne(event.ip_suppressed, 0); + else { + ptu_uint_eq(event.ip_suppressed, 0); + ptu_uint_eq(event.variant.tsx.ip, dfix->last_ip.ip); + } + ptu_int_eq(event.type, ptev_tsx); + ptu_int_eq(event.variant.tsx.speculative, + (flags & pt_mob_tsx_intx) != 0); + ptu_int_eq(event.variant.tsx.aborted, + (flags & pt_mob_tsx_abrt) != 0); + + if (!tsc) + ptu_int_eq(event.has_tsc, 0); + else { + ptu_int_eq(event.has_tsc, 1); + ptu_uint_eq(event.tsc, tsc); + } + + errcode = pt_qry_indirect_branch(decoder, &addr); + ptu_int_eq(errcode, pts_eos); + ptu_uint_eq(addr, tip.ip); + + return ptu_passed(); +} + +static struct ptunit_result +event_tsx_fup_cutoff_fail(struct ptu_decoder_fixture *dfix) +{ + struct pt_query_decoder *decoder = &dfix->decoder; + struct pt_encoder *encoder = &dfix->encoder; + struct pt_event event; + int errcode; + + pt_encode_mode_tsx(encoder, 0); + pt_encode_fup(encoder, 0, pt_ipc_update_16); + + ptu_check(cutoff, decoder, encoder); + ptu_check(ptu_sync_decoder, decoder); + + errcode = pt_qry_event(decoder, &event, sizeof(event)); + ptu_int_eq(errcode, -pte_eos); + + return ptu_passed(); +} + +static struct ptunit_result +event_tsx_cutoff_fail(struct ptu_decoder_fixture *dfix) +{ + struct pt_query_decoder *decoder = &dfix->decoder; + struct pt_encoder *encoder = &dfix->encoder; + struct pt_event event; + int errcode; + + pt_encode_mode_tsx(encoder, 0); + + ptu_check(cutoff, decoder, encoder); + ptu_check(ptu_sync_decoder, decoder); + + errcode = pt_qry_event(decoder, &event, sizeof(event)); + ptu_int_eq(errcode, -pte_eos); + + return ptu_passed(); +} + +static struct ptunit_result +event_skip_tip_fail(struct ptu_decoder_fixture *dfix) +{ + struct pt_query_decoder *decoder = &dfix->decoder; + struct pt_encoder *encoder = &dfix->encoder; + struct pt_event event; + const uint8_t *pos; + int errcode; + + pos = encoder->pos; + pt_encode_tip(encoder, 0, pt_ipc_sext_48); + /* We omit the actual event - we don't get that far, anyway. */ + + ptu_check(ptu_sync_decoder, decoder); + + errcode = pt_qry_event(decoder, &event, sizeof(event)); + ptu_int_eq(errcode, -pte_bad_query); + ptu_ptr_eq(decoder->pos, pos); + + return ptu_passed(); +} + +static struct ptunit_result +event_skip_tnt_8_fail(struct ptu_decoder_fixture *dfix) +{ + struct pt_query_decoder *decoder = &dfix->decoder; + struct pt_encoder *encoder = &dfix->encoder; + struct pt_event event; + int errcode; + + pt_encode_tnt_8(encoder, 0, 1); + pt_encode_tnt_8(encoder, 0, 1); + /* We omit the actual event - we don't get that far, anyway. */ + + ptu_check(ptu_sync_decoder, decoder); + + errcode = pt_qry_event(decoder, &event, sizeof(event)); + ptu_int_eq(errcode, -pte_bad_query); + /* The fail position depends on the fixture's header. */ + + return ptu_passed(); +} + +static struct ptunit_result +event_skip_tnt_64_fail(struct ptu_decoder_fixture *dfix) +{ + struct pt_query_decoder *decoder = &dfix->decoder; + struct pt_encoder *encoder = &dfix->encoder; + struct pt_event event; + int errcode; + + pt_encode_tnt_64(encoder, 0, 1); + pt_encode_tnt_64(encoder, 0, 1); + /* We omit the actual event - we don't get that far, anyway. */ + + ptu_check(ptu_sync_decoder, decoder); + + errcode = pt_qry_event(decoder, &event, sizeof(event)); + ptu_int_eq(errcode, -pte_bad_query); + /* The fail position depends on the fixture's header. */ + + return ptu_passed(); +} + +static struct ptunit_result sync_event(struct ptu_decoder_fixture *dfix, + enum pt_ip_compression ipc) +{ + struct pt_query_decoder *decoder = &dfix->decoder; + struct pt_encoder *encoder = &dfix->encoder; + struct pt_packet_ip packet; + struct pt_event event; + uint64_t addr = 0ull; + int errcode; + + packet.ipc = ipc; + packet.ip = 0xccull; + + pt_last_ip_init(&dfix->last_ip); + pt_last_ip_update_ip(&dfix->last_ip, &packet, &dfix->config); + + pt_encode_psb(encoder); + pt_encode_mode_tsx(encoder, pt_mob_tsx_intx); + pt_encode_fup(encoder, packet.ip, packet.ipc); + pt_encode_psbend(encoder); + + errcode = pt_qry_sync_forward(decoder, &addr); + switch (ipc) { + case pt_ipc_suppressed: + ptu_int_eq(errcode, (pts_event_pending | pts_ip_suppressed)); + break; + + case pt_ipc_update_16: + case pt_ipc_update_32: + case pt_ipc_update_48: + case pt_ipc_sext_48: + case pt_ipc_full: + ptu_int_eq(errcode, pts_event_pending); + ptu_uint_eq(addr, dfix->last_ip.ip); + break; + } + + errcode = pt_qry_event(decoder, &event, sizeof(event)); + ptu_int_eq(errcode, pts_eos); + ptu_uint_ne(event.status_update, 0); + if (ipc == pt_ipc_suppressed) + ptu_uint_ne(event.ip_suppressed, 0); + else { + ptu_uint_eq(event.ip_suppressed, 0); + ptu_uint_eq(event.variant.tsx.ip, dfix->last_ip.ip); + } + ptu_int_eq(event.type, ptev_tsx); + ptu_int_eq(event.variant.tsx.speculative, 1); + ptu_int_eq(event.variant.tsx.aborted, 0); + ptu_int_eq(event.has_tsc, 0); + + return ptu_passed(); +} + +static struct ptunit_result +sync_event_cutoff_fail(struct ptu_decoder_fixture *dfix) +{ + struct pt_query_decoder *decoder = &dfix->decoder; + struct pt_encoder *encoder = &dfix->encoder; + uint64_t addr; + int errcode; + + pt_encode_psb(encoder); + pt_encode_psbend(encoder); + + ptu_check(cutoff, decoder, encoder); + + errcode = pt_qry_sync_forward(decoder, &addr); + ptu_int_eq(errcode, -pte_eos); + + return ptu_passed(); +} + +static struct ptunit_result +sync_event_incomplete_fail(struct ptu_decoder_fixture *dfix) +{ + struct pt_query_decoder *decoder = &dfix->decoder; + struct pt_encoder *encoder = &dfix->encoder; + uint64_t addr; + int errcode; + + pt_encode_psb(encoder); + + errcode = pt_qry_sync_forward(decoder, &addr); + ptu_int_eq(errcode, -pte_eos); + + return ptu_passed(); +} + +static struct ptunit_result sync_ovf_event(struct ptu_decoder_fixture *dfix, + enum pt_ip_compression ipc) +{ + struct pt_query_decoder *decoder = &dfix->decoder; + struct pt_encoder *encoder = &dfix->encoder; + struct pt_packet_ip fup, ovf; + struct pt_event event; + uint64_t addr = 0; + int errcode; + + fup.ipc = pt_ipc_sext_48; + fup.ip = pt_dfix_max_ip; + + ovf.ipc = ipc; + ovf.ip = 0xccull; + + pt_last_ip_init(&dfix->last_ip); + pt_last_ip_update_ip(&dfix->last_ip, &ovf, &dfix->config); + + pt_encode_psb(encoder); + pt_encode_fup(encoder, fup.ip, fup.ipc); + pt_encode_mode_tsx(encoder, 0); + pt_encode_tsc(encoder, 0x1000); + pt_encode_ovf(encoder); + pt_encode_fup(encoder, ovf.ip, ovf.ipc); + + errcode = pt_qry_sync_forward(decoder, &addr); + ptu_int_eq(errcode, pts_event_pending); + ptu_uint_eq(addr, fup.ip); + + errcode = pt_qry_event(decoder, &event, sizeof(event)); + ptu_int_eq(errcode, pts_event_pending); + ptu_uint_ne(event.status_update, 0); + ptu_int_eq(event.type, ptev_tsx); + ptu_int_eq(event.variant.tsx.speculative, 0); + ptu_int_eq(event.variant.tsx.aborted, 0); + ptu_uint_eq(event.variant.tsx.ip, fup.ip); + ptu_int_eq(event.has_tsc, 1); + ptu_uint_eq(event.tsc, 0x1000); + + errcode = pt_qry_event(decoder, &event, sizeof(event)); + switch (ipc) { + case pt_ipc_suppressed: + ptu_int_eq(errcode, -pte_noip); + return ptu_passed(); + + case pt_ipc_update_16: + case pt_ipc_update_32: + case pt_ipc_update_48: + case pt_ipc_sext_48: + case pt_ipc_full: + ptu_int_eq(errcode, pts_eos); + ptu_int_eq(event.type, ptev_overflow); + ptu_uint_eq(event.variant.overflow.ip, dfix->last_ip.ip); + ptu_int_eq(event.has_tsc, 1); + ptu_uint_eq(event.tsc, 0x1000); + break; + } + + return ptu_passed(); +} + +static struct ptunit_result +sync_ovf_event_cutoff_fail(struct ptu_decoder_fixture *dfix) +{ + struct pt_query_decoder *decoder = &dfix->decoder; + struct pt_encoder *encoder = &dfix->encoder; + uint64_t addr; + int errcode; + + pt_encode_psb(encoder); + pt_encode_ovf(encoder); + + ptu_check(cutoff, decoder, encoder); + + errcode = pt_qry_sync_forward(decoder, &addr); + ptu_int_eq(errcode, -pte_eos); + + return ptu_passed(); +} + +static struct ptunit_result time_null_fail(struct ptu_decoder_fixture *dfix) +{ + struct pt_query_decoder *decoder = &dfix->decoder; + uint64_t tsc; + int errcode; + + errcode = pt_qry_time(NULL, NULL, NULL, NULL); + ptu_int_eq(errcode, -pte_invalid); + + errcode = pt_qry_time(decoder, NULL, NULL, NULL); + ptu_int_eq(errcode, -pte_invalid); + + errcode = pt_qry_time(NULL, &tsc, NULL, NULL); + ptu_int_eq(errcode, -pte_invalid); + + return ptu_passed(); +} + +static struct ptunit_result time_initial(struct ptu_decoder_fixture *dfix) +{ + struct pt_query_decoder *decoder = &dfix->decoder; + uint64_t tsc; + int errcode; + + errcode = pt_qry_time(decoder, &tsc, NULL, NULL); + ptu_int_eq(errcode, -pte_no_time); + + return ptu_passed(); +} + +static struct ptunit_result time(struct ptu_decoder_fixture *dfix) +{ + struct pt_query_decoder *decoder = &dfix->decoder; + uint64_t tsc, exp; + int errcode; + + exp = 0x11223344556677ull; + + decoder->last_time.have_tsc = 1; + decoder->last_time.tsc = exp; + + errcode = pt_qry_time(decoder, &tsc, NULL, NULL); + ptu_int_eq(errcode, 0); + ptu_uint_eq(tsc, exp); + + return ptu_passed(); +} + +static struct ptunit_result cbr_null(struct ptu_decoder_fixture *dfix) +{ + struct pt_query_decoder *decoder = &dfix->decoder; + uint32_t cbr; + int errcode; + + errcode = pt_qry_core_bus_ratio(NULL, NULL); + ptu_int_eq(errcode, -pte_invalid); + + errcode = pt_qry_core_bus_ratio(decoder, NULL); + ptu_int_eq(errcode, -pte_invalid); + + errcode = pt_qry_core_bus_ratio(NULL, &cbr); + ptu_int_eq(errcode, -pte_invalid); + + return ptu_passed(); +} + +static struct ptunit_result cbr_initial(struct ptu_decoder_fixture *dfix) +{ + struct pt_query_decoder *decoder = &dfix->decoder; + uint32_t cbr; + int errcode; + + errcode = pt_qry_core_bus_ratio(decoder, &cbr); + ptu_int_eq(errcode, -pte_no_cbr); + + return ptu_passed(); +} + +static struct ptunit_result cbr(struct ptu_decoder_fixture *dfix) +{ + struct pt_query_decoder *decoder = &dfix->decoder; + uint32_t cbr; + int errcode; + + decoder->last_time.have_cbr = 1; + decoder->last_time.cbr = 42; + + errcode = pt_qry_core_bus_ratio(decoder, &cbr); + ptu_int_eq(errcode, 0); + ptu_uint_eq(cbr, 42); + + return ptu_passed(); +} + +/* Test that end-of-stream is indicated correctly when the stream ends with a + * partial non-query-relevant packet. + */ +static struct ptunit_result indir_cyc_cutoff(struct ptu_decoder_fixture *dfix) +{ + struct pt_query_decoder *decoder = &dfix->decoder; + struct pt_encoder *encoder = &dfix->encoder; + uint64_t ip; + int errcode; + + pt_encode_tip(encoder, 0xa000ull, pt_ipc_full); + pt_encode_cyc(encoder, 0xfff); + + ptu_check(cutoff, decoder, encoder); + ptu_check(ptu_sync_decoder, decoder); + + errcode = pt_qry_indirect_branch(decoder, &ip); + ptu_int_eq(errcode, pts_eos); + + return ptu_passed(); +} + +/* Test that end-of-stream is indicated correctly when the stream ends with a + * partial non-query-relevant packet. + */ +static struct ptunit_result cond_cyc_cutoff(struct ptu_decoder_fixture *dfix) +{ + struct pt_query_decoder *decoder = &dfix->decoder; + struct pt_encoder *encoder = &dfix->encoder; + int errcode, taken; + + pt_encode_tnt_8(encoder, 0, 1); + pt_encode_cyc(encoder, 0xfff); + + ptu_check(cutoff, decoder, encoder); + ptu_check(ptu_sync_decoder, decoder); + + errcode = pt_qry_cond_branch(decoder, &taken); + ptu_int_eq(errcode, pts_eos); + + return ptu_passed(); +} + +/* Test that end-of-stream is indicated correctly when the stream ends with a + * partial non-query-relevant packet. + */ +static struct ptunit_result event_cyc_cutoff(struct ptu_decoder_fixture *dfix) +{ + struct pt_query_decoder *decoder = &dfix->decoder; + struct pt_encoder *encoder = &dfix->encoder; + struct pt_event event; + int errcode; + + pt_encode_tip_pgd(encoder, 0ull, pt_ipc_full); + pt_encode_cyc(encoder, 0xffff); + + ptu_check(cutoff, decoder, encoder); + ptu_check(ptu_sync_decoder, decoder); + + errcode = pt_qry_event(decoder, &event, sizeof(event)); + ptu_int_eq(errcode, pts_eos); + + return ptu_passed(); +} + +static struct ptunit_result ptu_dfix_init(struct ptu_decoder_fixture *dfix) +{ + struct pt_config *config = &dfix->config; + int errcode; + + (void) memset(dfix->buffer, 0, sizeof(dfix->buffer)); + + pt_config_init(config); + + config->begin = dfix->buffer; + config->end = dfix->buffer + sizeof(dfix->buffer); + + errcode = pt_encoder_init(&dfix->encoder, config); + ptu_int_eq(errcode, 0); + + errcode = pt_qry_decoder_init(&dfix->decoder, config); + ptu_int_eq(errcode, 0); + + dfix->decoder.ip.ip = pt_dfix_bad_ip; + dfix->decoder.ip.have_ip = 1; + dfix->decoder.ip.suppressed = 0; + + dfix->last_ip = dfix->decoder.ip; + + if (dfix->header) + dfix->header(dfix); + + return ptu_passed(); +} + +static struct ptunit_result ptu_dfix_fini(struct ptu_decoder_fixture *dfix) +{ + pt_qry_decoder_fini(&dfix->decoder); + pt_encoder_fini(&dfix->encoder); + + return ptu_passed(); +} + +/* Synchronize the decoder at the beginnig of an empty buffer. */ +static struct ptunit_result +ptu_dfix_header_sync(struct ptu_decoder_fixture *dfix) +{ + struct pt_query_decoder *decoder = &dfix->decoder; + + /* Synchronize the decoder at the beginning of the buffer. */ + decoder->pos = decoder->config.begin; + + return ptu_passed(); +} + +/* Synchronize the decoder at the beginnig of a buffer containing packets that + * should be skipped for unconditional indirect branch queries. + */ +static struct ptunit_result +ptu_dfix_header_indir(struct ptu_decoder_fixture *dfix) +{ + struct pt_query_decoder *decoder = &dfix->decoder; + struct pt_encoder *encoder = &dfix->encoder; + + pt_encode_pad(encoder); + pt_encode_mtc(encoder, 1); + pt_encode_pad(encoder); + pt_encode_tsc(encoder, 0); + + /* Synchronize the decoder at the beginning of the buffer. */ + decoder->pos = decoder->config.begin; + + return ptu_passed(); +} + +/* Synchronize the decoder at the beginnig of a buffer containing packets that + * should be skipped for unconditional indirect branch queries including a PSB. + */ +static struct ptunit_result +ptu_dfix_header_indir_psb(struct ptu_decoder_fixture *dfix) +{ + struct pt_query_decoder *decoder = &dfix->decoder; + struct pt_encoder *encoder = &dfix->encoder; + + /* The psb must be empty since the tests won't skip status events. + * On the other hand, we do need to provide an address since tests + * may want to update last-ip, which requires a last-ip, of course. + */ + pt_encode_pad(encoder); + pt_encode_tsc(encoder, 0); + pt_encode_psb(encoder); + pt_encode_mtc(encoder, 1); + pt_encode_pad(encoder); + pt_encode_tsc(encoder, 0); + pt_encode_fup(encoder, pt_dfix_sext_ip, pt_ipc_sext_48); + pt_encode_psbend(encoder); + pt_encode_mtc(encoder, 1); + pt_encode_pad(encoder); + + /* Synchronize the decoder at the beginning of the buffer. */ + decoder->pos = decoder->config.begin; + + return ptu_passed(); +} + +/* Synchronize the decoder at the beginnig of a buffer containing packets that + * should be skipped for conditional branch queries. + */ +static struct ptunit_result +ptu_dfix_header_cond(struct ptu_decoder_fixture *dfix) +{ + struct pt_query_decoder *decoder = &dfix->decoder; + struct pt_encoder *encoder = &dfix->encoder; + + /* The psb must be empty since the tests won't skip status events. + * On the other hand, we do need to provide an address since tests + * may want to update last-ip, which requires a last-ip, of course. + */ + pt_encode_pad(encoder); + pt_encode_mtc(encoder, 1); + pt_encode_psb(encoder); + pt_encode_tsc(encoder, 0); + pt_encode_pad(encoder); + pt_encode_fup(encoder, pt_dfix_sext_ip, pt_ipc_sext_48); + pt_encode_psbend(encoder); + pt_encode_pad(encoder); + pt_encode_tsc(encoder, 0); + pt_encode_pad(encoder); + + /* Synchronize the decoder at the beginning of the buffer. */ + decoder->pos = decoder->config.begin; + + return ptu_passed(); +} + +/* Synchronize the decoder at the beginnig of a buffer containing packets that + * should be skipped for event queries. + */ +static struct ptunit_result +ptu_dfix_header_event(struct ptu_decoder_fixture *dfix) +{ + struct pt_query_decoder *decoder = &dfix->decoder; + struct pt_encoder *encoder = &dfix->encoder; + + pt_encode_pad(encoder); + pt_encode_mtc(encoder, 1); + pt_encode_pad(encoder); + pt_encode_tsc(encoder, 0x1000); + + /* Synchronize the decoder at the beginning of the buffer. */ + decoder->pos = decoder->config.begin; + + return ptu_passed(); +} + +/* Synchronize the decoder at the beginnig of a buffer containing packets that + * should be skipped for event queries including a PSB. + */ +static struct ptunit_result +ptu_dfix_header_event_psb(struct ptu_decoder_fixture *dfix) +{ + struct pt_query_decoder *decoder = &dfix->decoder; + struct pt_encoder *encoder = &dfix->encoder; + + /* The psb must be empty since the tests won't skip status events. + * On the other hand, we do need to provide an address since tests + * may want to update last-ip, which requires a last-ip, of course. + */ + pt_encode_pad(encoder); + pt_encode_tsc(encoder, 0); + pt_encode_psb(encoder); + pt_encode_mtc(encoder, 1); + pt_encode_pad(encoder); + pt_encode_tsc(encoder, 0x1000); + pt_encode_fup(encoder, pt_dfix_sext_ip, pt_ipc_sext_48); + pt_encode_psbend(encoder); + pt_encode_mtc(encoder, 1); + pt_encode_pad(encoder); + + /* Synchronize the decoder at the beginning of the buffer. */ + decoder->pos = decoder->config.begin; + + return ptu_passed(); +} + +static struct ptu_decoder_fixture dfix_raw; +static struct ptu_decoder_fixture dfix_empty; +static struct ptu_decoder_fixture dfix_indir; +static struct ptu_decoder_fixture dfix_indir_psb; +static struct ptu_decoder_fixture dfix_cond; +static struct ptu_decoder_fixture dfix_event; +static struct ptu_decoder_fixture dfix_event_psb; + +static void init_fixtures(void) +{ + dfix_raw.init = ptu_dfix_init; + dfix_raw.fini = ptu_dfix_fini; + + dfix_empty = dfix_raw; + dfix_empty.header = ptu_dfix_header_sync; + + dfix_indir = dfix_raw; + dfix_indir.header = ptu_dfix_header_indir; + + dfix_indir_psb = dfix_raw; + dfix_indir_psb.header = ptu_dfix_header_indir_psb; + + dfix_cond = dfix_raw; + dfix_cond.header = ptu_dfix_header_cond; + + dfix_event = dfix_raw; + dfix_event.header = ptu_dfix_header_event; + + dfix_event_psb = dfix_raw; + dfix_event_psb.header = ptu_dfix_header_event_psb; +} + +int main(int argc, char **argv) +{ + struct ptunit_suite suite; + + init_fixtures(); + + suite = ptunit_mk_suite(argc, argv); + + ptu_run_f(suite, indir_not_synced, dfix_raw); + ptu_run_f(suite, cond_not_synced, dfix_raw); + ptu_run_f(suite, event_not_synced, dfix_raw); + + ptu_run_f(suite, sync_backward, dfix_raw); + ptu_run_f(suite, sync_backward_empty_end, dfix_raw); + ptu_run_f(suite, sync_backward_empty_mid, dfix_raw); + ptu_run_f(suite, sync_backward_empty_begin, dfix_raw); + ptu_run_f(suite, decode_sync_backward, dfix_raw); + + ptu_run_f(suite, indir_null, dfix_empty); + ptu_run_f(suite, indir_empty, dfix_empty); + ptu_run_fp(suite, indir, dfix_empty, pt_ipc_suppressed); + ptu_run_fp(suite, indir, dfix_empty, pt_ipc_update_16); + ptu_run_fp(suite, indir, dfix_empty, pt_ipc_update_32); + ptu_run_fp(suite, indir, dfix_empty, pt_ipc_update_48); + ptu_run_fp(suite, indir, dfix_empty, pt_ipc_sext_48); + ptu_run_fp(suite, indir, dfix_empty, pt_ipc_full); + ptu_run_fp(suite, indir_tnt, dfix_empty, pt_ipc_suppressed); + ptu_run_fp(suite, indir_tnt, dfix_empty, pt_ipc_update_16); + ptu_run_fp(suite, indir_tnt, dfix_empty, pt_ipc_update_32); + ptu_run_fp(suite, indir_tnt, dfix_empty, pt_ipc_update_48); + ptu_run_fp(suite, indir_tnt, dfix_empty, pt_ipc_sext_48); + ptu_run_fp(suite, indir_tnt, dfix_empty, pt_ipc_full); + ptu_run_f(suite, indir_cutoff_fail, dfix_empty); + ptu_run_f(suite, indir_skip_tnt_fail, dfix_empty); + ptu_run_f(suite, indir_skip_tip_pge_fail, dfix_empty); + ptu_run_f(suite, indir_skip_tip_pgd_fail, dfix_empty); + ptu_run_f(suite, indir_skip_fup_tip_fail, dfix_empty); + ptu_run_f(suite, indir_skip_fup_tip_pgd_fail, dfix_empty); + + ptu_run_fp(suite, indir, dfix_indir, pt_ipc_suppressed); + ptu_run_fp(suite, indir, dfix_indir, pt_ipc_update_16); + ptu_run_fp(suite, indir, dfix_indir, pt_ipc_update_32); + ptu_run_fp(suite, indir, dfix_indir, pt_ipc_update_48); + ptu_run_fp(suite, indir, dfix_indir, pt_ipc_sext_48); + ptu_run_fp(suite, indir, dfix_indir, pt_ipc_full); + ptu_run_fp(suite, indir_tnt, dfix_indir, pt_ipc_suppressed); + ptu_run_fp(suite, indir_tnt, dfix_indir, pt_ipc_update_16); + ptu_run_fp(suite, indir_tnt, dfix_indir, pt_ipc_update_32); + ptu_run_fp(suite, indir_tnt, dfix_indir, pt_ipc_update_48); + ptu_run_fp(suite, indir_tnt, dfix_indir, pt_ipc_sext_48); + ptu_run_fp(suite, indir_tnt, dfix_indir, pt_ipc_full); + ptu_run_f(suite, indir_cutoff_fail, dfix_indir); + ptu_run_f(suite, indir_skip_tnt_fail, dfix_indir); + ptu_run_f(suite, indir_skip_tip_pge_fail, dfix_indir); + ptu_run_f(suite, indir_skip_tip_pgd_fail, dfix_indir); + ptu_run_f(suite, indir_skip_fup_tip_fail, dfix_indir); + ptu_run_f(suite, indir_skip_fup_tip_pgd_fail, dfix_indir); + + ptu_run_fp(suite, indir, dfix_indir_psb, pt_ipc_suppressed); + ptu_run_fp(suite, indir, dfix_indir_psb, pt_ipc_sext_48); + ptu_run_fp(suite, indir, dfix_indir_psb, pt_ipc_full); + ptu_run_fp(suite, indir_tnt, dfix_indir_psb, pt_ipc_suppressed); + ptu_run_fp(suite, indir_tnt, dfix_indir_psb, pt_ipc_sext_48); + ptu_run_fp(suite, indir_tnt, dfix_indir_psb, pt_ipc_full); + ptu_run_f(suite, indir_cutoff_fail, dfix_indir_psb); + ptu_run_f(suite, indir_skip_tnt_fail, dfix_indir_psb); + ptu_run_f(suite, indir_skip_tip_pge_fail, dfix_indir_psb); + ptu_run_f(suite, indir_skip_tip_pgd_fail, dfix_indir_psb); + ptu_run_f(suite, indir_skip_fup_tip_fail, dfix_indir_psb); + ptu_run_f(suite, indir_skip_fup_tip_pgd_fail, dfix_indir_psb); + + ptu_run_f(suite, cond_null, dfix_empty); + ptu_run_f(suite, cond_empty, dfix_empty); + ptu_run_f(suite, cond, dfix_empty); + ptu_run_f(suite, cond_skip_tip_fail, dfix_empty); + ptu_run_f(suite, cond_skip_tip_pge_fail, dfix_empty); + ptu_run_f(suite, cond_skip_tip_pgd_fail, dfix_empty); + ptu_run_f(suite, cond_skip_fup_tip_fail, dfix_empty); + ptu_run_f(suite, cond_skip_fup_tip_pgd_fail, dfix_empty); + + ptu_run_f(suite, cond, dfix_cond); + ptu_run_f(suite, cond_skip_tip_fail, dfix_cond); + ptu_run_f(suite, cond_skip_tip_pge_fail, dfix_cond); + ptu_run_f(suite, cond_skip_tip_pgd_fail, dfix_cond); + ptu_run_f(suite, cond_skip_fup_tip_fail, dfix_cond); + ptu_run_f(suite, cond_skip_fup_tip_pgd_fail, dfix_cond); + + ptu_run_f(suite, event_null, dfix_empty); + ptu_run_f(suite, event_bad_size, dfix_empty); + ptu_run_f(suite, event_small_size, dfix_empty); + ptu_run_f(suite, event_big_size, dfix_empty); + ptu_run_f(suite, event_empty, dfix_empty); + ptu_run_fp(suite, event_enabled, dfix_empty, pt_ipc_suppressed, 0); + ptu_run_fp(suite, event_enabled, dfix_empty, pt_ipc_update_16, 0); + ptu_run_fp(suite, event_enabled, dfix_empty, pt_ipc_update_32, 0); + ptu_run_fp(suite, event_enabled, dfix_empty, pt_ipc_update_48, 0); + ptu_run_fp(suite, event_enabled, dfix_empty, pt_ipc_sext_48, 0); + ptu_run_fp(suite, event_enabled, dfix_empty, pt_ipc_full, 0); + ptu_run_f(suite, event_enabled_cutoff_fail, dfix_empty); + ptu_run_fp(suite, event_disabled, dfix_empty, pt_ipc_suppressed, 0); + ptu_run_fp(suite, event_disabled, dfix_empty, pt_ipc_update_16, 0); + ptu_run_fp(suite, event_disabled, dfix_empty, pt_ipc_update_32, 0); + ptu_run_fp(suite, event_disabled, dfix_empty, pt_ipc_update_48, 0); + ptu_run_fp(suite, event_disabled, dfix_empty, pt_ipc_sext_48, 0); + ptu_run_fp(suite, event_disabled, dfix_empty, pt_ipc_full, 0); + ptu_run_f(suite, event_disabled_cutoff_fail, dfix_empty); + ptu_run_fp(suite, event_async_disabled, dfix_empty, pt_ipc_suppressed, + 0); + ptu_run_fp(suite, event_async_disabled, dfix_empty, pt_ipc_update_16, + 0); + ptu_run_fp(suite, event_async_disabled, dfix_empty, pt_ipc_update_32, + 0); + ptu_run_fp(suite, event_async_disabled, dfix_empty, pt_ipc_update_48, + 0); + ptu_run_fp(suite, event_async_disabled, dfix_empty, pt_ipc_sext_48, 0); + ptu_run_fp(suite, event_async_disabled, dfix_empty, pt_ipc_full, 0); + ptu_run_f(suite, event_async_disabled_suppressed_fail, dfix_empty); + ptu_run_f(suite, event_async_disabled_cutoff_fail_a, dfix_empty); + ptu_run_f(suite, event_async_disabled_cutoff_fail_b, dfix_empty); + ptu_run_fp(suite, event_async_branch, dfix_empty, pt_ipc_suppressed, 0); + ptu_run_fp(suite, event_async_branch, dfix_empty, pt_ipc_update_16, 0); + ptu_run_fp(suite, event_async_branch, dfix_empty, pt_ipc_update_32, 0); + ptu_run_fp(suite, event_async_branch, dfix_empty, pt_ipc_update_48, 0); + ptu_run_fp(suite, event_async_branch, dfix_empty, pt_ipc_sext_48, 0); + ptu_run_fp(suite, event_async_branch, dfix_empty, pt_ipc_full, 0); + ptu_run_f(suite, event_async_branch_suppressed_fail, dfix_empty); + ptu_run_f(suite, event_async_branch_cutoff_fail_a, dfix_empty); + ptu_run_f(suite, event_async_branch_cutoff_fail_b, dfix_empty); + ptu_run_fp(suite, event_paging, dfix_empty, 0, 0); + ptu_run_fp(suite, event_paging, dfix_empty, pt_pl_pip_nr, 0); + ptu_run_f(suite, event_paging_cutoff_fail, dfix_empty); + ptu_run_fp(suite, event_async_paging, dfix_empty, 0, 0); + ptu_run_fp(suite, event_async_paging, dfix_empty, pt_pl_pip_nr, 0); + ptu_run_fp(suite, event_async_paging_suppressed, dfix_empty, 0, 0); + ptu_run_fp(suite, event_async_paging_suppressed, dfix_empty, + pt_pl_pip_nr, 0); + ptu_run_f(suite, event_async_paging_cutoff_fail, dfix_empty); + ptu_run_fp(suite, event_overflow_fup, dfix_empty, pt_ipc_suppressed, 0); + ptu_run_fp(suite, event_overflow_fup, dfix_empty, pt_ipc_update_16, 0); + ptu_run_fp(suite, event_overflow_fup, dfix_empty, pt_ipc_update_32, 0); + ptu_run_fp(suite, event_overflow_fup, dfix_empty, pt_ipc_update_48, 0); + ptu_run_fp(suite, event_overflow_fup, dfix_empty, pt_ipc_sext_48, 0); + ptu_run_fp(suite, event_overflow_fup, dfix_empty, pt_ipc_full, 0); + ptu_run_fp(suite, event_overflow_tip_pge, dfix_empty, + pt_ipc_suppressed, 0); + ptu_run_fp(suite, event_overflow_tip_pge, dfix_empty, pt_ipc_update_16, + 0); + ptu_run_fp(suite, event_overflow_tip_pge, dfix_empty, pt_ipc_update_32, + 0); + ptu_run_fp(suite, event_overflow_tip_pge, dfix_empty, pt_ipc_update_48, + 0); + ptu_run_fp(suite, event_overflow_tip_pge, dfix_empty, pt_ipc_sext_48, + 0); + ptu_run_fp(suite, event_overflow_tip_pge, dfix_empty, pt_ipc_full, + 0); + ptu_run_f(suite, event_overflow_cutoff_fail, dfix_empty); + ptu_run_fp(suite, event_stop, dfix_empty, 0); + ptu_run_fp(suite, event_exec_mode_tip, dfix_empty, pt_ipc_suppressed, + 0); + ptu_run_fp(suite, event_exec_mode_tip, dfix_empty, pt_ipc_update_16, 0); + ptu_run_fp(suite, event_exec_mode_tip, dfix_empty, pt_ipc_update_32, 0); + ptu_run_fp(suite, event_exec_mode_tip, dfix_empty, pt_ipc_update_48, 0); + ptu_run_fp(suite, event_exec_mode_tip, dfix_empty, pt_ipc_sext_48, 0); + ptu_run_fp(suite, event_exec_mode_tip, dfix_empty, pt_ipc_full, 0); + ptu_run_f(suite, event_exec_mode_tip_cutoff_fail, dfix_empty); + ptu_run_fp(suite, event_exec_mode_tip_pge, dfix_empty, + pt_ipc_suppressed, 0); + ptu_run_fp(suite, event_exec_mode_tip_pge, dfix_empty, + pt_ipc_update_16, 0); + ptu_run_fp(suite, event_exec_mode_tip_pge, dfix_empty, + pt_ipc_update_32, 0); + ptu_run_fp(suite, event_exec_mode_tip_pge, dfix_empty, + pt_ipc_update_48, 0); + ptu_run_fp(suite, event_exec_mode_tip_pge, dfix_empty, pt_ipc_sext_48, + 0); + ptu_run_fp(suite, event_exec_mode_tip_pge, dfix_empty, pt_ipc_full, + 0); + ptu_run_f(suite, event_exec_mode_tip_pge_cutoff_fail, dfix_empty); + ptu_run_f(suite, event_exec_mode_cutoff_fail, dfix_empty); + ptu_run_fp(suite, event_tsx_fup, dfix_empty, pt_ipc_suppressed, + pt_mob_tsx_intx, 0); + ptu_run_fp(suite, event_tsx_fup, dfix_empty, pt_ipc_update_16, 0, 0); + ptu_run_fp(suite, event_tsx_fup, dfix_empty, pt_ipc_update_32, + pt_mob_tsx_intx, 0); + ptu_run_fp(suite, event_tsx_fup, dfix_empty, pt_ipc_update_48, + pt_mob_tsx_intx, 0); + ptu_run_fp(suite, event_tsx_fup, dfix_empty, pt_ipc_sext_48, 0, 0); + ptu_run_fp(suite, event_tsx_fup, dfix_empty, pt_ipc_full, 0, 0); + ptu_run_f(suite, event_tsx_fup_cutoff_fail, dfix_empty); + ptu_run_f(suite, event_tsx_cutoff_fail, dfix_empty); + ptu_run_f(suite, event_skip_tip_fail, dfix_empty); + ptu_run_f(suite, event_skip_tnt_8_fail, dfix_empty); + ptu_run_f(suite, event_skip_tnt_64_fail, dfix_empty); + ptu_run_fp(suite, sync_event, dfix_empty, pt_ipc_suppressed); + ptu_run_fp(suite, sync_event, dfix_empty, pt_ipc_update_16); + ptu_run_fp(suite, sync_event, dfix_empty, pt_ipc_update_32); + ptu_run_fp(suite, sync_event, dfix_empty, pt_ipc_update_48); + ptu_run_fp(suite, sync_event, dfix_empty, pt_ipc_sext_48); + ptu_run_fp(suite, sync_event, dfix_empty, pt_ipc_full); + ptu_run_f(suite, sync_event_cutoff_fail, dfix_empty); + ptu_run_f(suite, sync_event_incomplete_fail, dfix_empty); + ptu_run_fp(suite, sync_ovf_event, dfix_empty, pt_ipc_suppressed); + ptu_run_fp(suite, sync_ovf_event, dfix_empty, pt_ipc_update_16); + ptu_run_fp(suite, sync_ovf_event, dfix_empty, pt_ipc_update_32); + ptu_run_fp(suite, sync_ovf_event, dfix_empty, pt_ipc_update_48); + ptu_run_fp(suite, sync_ovf_event, dfix_empty, pt_ipc_sext_48); + ptu_run_fp(suite, sync_ovf_event, dfix_empty, pt_ipc_full); + ptu_run_f(suite, sync_ovf_event_cutoff_fail, dfix_empty); + + ptu_run_fp(suite, event_enabled, dfix_event, pt_ipc_suppressed, 0x1000); + ptu_run_fp(suite, event_enabled, dfix_event, pt_ipc_update_16, 0x1000); + ptu_run_fp(suite, event_enabled, dfix_event, pt_ipc_update_32, 0x1000); + ptu_run_fp(suite, event_enabled, dfix_event, pt_ipc_update_48, 0x1000); + ptu_run_fp(suite, event_enabled, dfix_event, pt_ipc_sext_48, 0x1000); + ptu_run_fp(suite, event_enabled, dfix_event, pt_ipc_full, 0x1000); + ptu_run_f(suite, event_enabled_cutoff_fail, dfix_event); + ptu_run_fp(suite, event_disabled, dfix_event, pt_ipc_suppressed, + 0x1000); + ptu_run_fp(suite, event_disabled, dfix_event, pt_ipc_update_16, 0x1000); + ptu_run_fp(suite, event_disabled, dfix_event, pt_ipc_update_32, 0x1000); + ptu_run_fp(suite, event_disabled, dfix_event, pt_ipc_update_48, 0x1000); + ptu_run_fp(suite, event_disabled, dfix_event, pt_ipc_sext_48, 0x1000); + ptu_run_fp(suite, event_disabled, dfix_event, pt_ipc_full, 0x1000); + ptu_run_f(suite, event_disabled_cutoff_fail, dfix_event); + ptu_run_fp(suite, event_async_disabled, dfix_event, pt_ipc_suppressed, + 0x1000); + ptu_run_fp(suite, event_async_disabled, dfix_event, pt_ipc_update_16, + 0x1000); + ptu_run_fp(suite, event_async_disabled, dfix_event, pt_ipc_update_32, + 0x1000); + ptu_run_fp(suite, event_async_disabled, dfix_event, pt_ipc_update_48, + 0x1000); + ptu_run_fp(suite, event_async_disabled, dfix_event, pt_ipc_sext_48, + 0x1000); + ptu_run_fp(suite, event_async_disabled, dfix_event, pt_ipc_full, + 0x1000); + ptu_run_f(suite, event_async_disabled_suppressed_fail, dfix_event); + ptu_run_f(suite, event_async_disabled_cutoff_fail_a, dfix_event); + ptu_run_f(suite, event_async_disabled_cutoff_fail_b, dfix_event); + ptu_run_fp(suite, event_async_branch, dfix_event, pt_ipc_suppressed, + 0x1000); + ptu_run_fp(suite, event_async_branch, dfix_event, pt_ipc_update_16, + 0x1000); + ptu_run_fp(suite, event_async_branch, dfix_event, pt_ipc_update_32, + 0x1000); + ptu_run_fp(suite, event_async_branch, dfix_event, pt_ipc_update_48, + 0x1000); + ptu_run_fp(suite, event_async_branch, dfix_event, pt_ipc_sext_48, + 0x1000); + ptu_run_fp(suite, event_async_branch, dfix_event, pt_ipc_full, + 0x1000); + ptu_run_f(suite, event_async_branch_suppressed_fail, dfix_event); + ptu_run_f(suite, event_async_branch_cutoff_fail_a, dfix_event); + ptu_run_f(suite, event_async_branch_cutoff_fail_b, dfix_event); + ptu_run_fp(suite, event_paging, dfix_event, 0, 0x1000); + ptu_run_fp(suite, event_paging, dfix_event, pt_pl_pip_nr, 0x1000); + ptu_run_f(suite, event_paging_cutoff_fail, dfix_event); + ptu_run_fp(suite, event_async_paging, dfix_event, 0, 0x1000); + ptu_run_fp(suite, event_async_paging, dfix_event, pt_pl_pip_nr, 0x1000); + ptu_run_fp(suite, event_async_paging_suppressed, dfix_event, 0, 0x1000); + ptu_run_fp(suite, event_async_paging_suppressed, dfix_event, + pt_pl_pip_nr, 0x1000); + ptu_run_f(suite, event_async_paging_cutoff_fail, dfix_event); + ptu_run_fp(suite, event_overflow_fup, dfix_event, pt_ipc_suppressed, + 0x1000); + ptu_run_fp(suite, event_overflow_fup, dfix_event, pt_ipc_update_16, + 0x1000); + ptu_run_fp(suite, event_overflow_fup, dfix_event, pt_ipc_update_32, + 0x1000); + ptu_run_fp(suite, event_overflow_fup, dfix_event, pt_ipc_update_48, + 0x1000); + ptu_run_fp(suite, event_overflow_fup, dfix_event, pt_ipc_sext_48, + 0x1000); + ptu_run_fp(suite, event_overflow_fup, dfix_event, pt_ipc_full, + 0x1000); + ptu_run_fp(suite, event_overflow_tip_pge, dfix_event, + pt_ipc_suppressed, 0x1000); + ptu_run_fp(suite, event_overflow_tip_pge, dfix_event, pt_ipc_update_16, + 0x1000); + ptu_run_fp(suite, event_overflow_tip_pge, dfix_event, pt_ipc_update_32, + 0x1000); + ptu_run_fp(suite, event_overflow_tip_pge, dfix_event, pt_ipc_update_48, + 0x1000); + ptu_run_fp(suite, event_overflow_tip_pge, dfix_event, pt_ipc_sext_48, + 0x1000); + ptu_run_fp(suite, event_overflow_tip_pge, dfix_event, pt_ipc_full, + 0x1000); + ptu_run_f(suite, event_overflow_cutoff_fail, dfix_event); + ptu_run_fp(suite, event_stop, dfix_event, 0x1000); + ptu_run_fp(suite, event_exec_mode_tip, dfix_event, pt_ipc_suppressed, + 0x1000); + ptu_run_fp(suite, event_exec_mode_tip, dfix_event, pt_ipc_update_16, + 0x1000); + ptu_run_fp(suite, event_exec_mode_tip, dfix_event, pt_ipc_update_32, + 0x1000); + ptu_run_fp(suite, event_exec_mode_tip, dfix_event, pt_ipc_update_48, + 0x1000); + ptu_run_fp(suite, event_exec_mode_tip, dfix_event, pt_ipc_sext_48, + 0x1000); + ptu_run_fp(suite, event_exec_mode_tip, dfix_event, pt_ipc_full, + 0x1000); + ptu_run_f(suite, event_exec_mode_tip_cutoff_fail, dfix_event); + ptu_run_fp(suite, event_exec_mode_tip_pge, dfix_event, + pt_ipc_suppressed, 0x1000); + ptu_run_fp(suite, event_exec_mode_tip_pge, dfix_event, + pt_ipc_update_16, 0x1000); + ptu_run_fp(suite, event_exec_mode_tip_pge, dfix_event, + pt_ipc_update_32, 0x1000); + ptu_run_fp(suite, event_exec_mode_tip_pge, dfix_event, + pt_ipc_update_48, 0x1000); + ptu_run_fp(suite, event_exec_mode_tip_pge, dfix_event, pt_ipc_sext_48, + 0x1000); + ptu_run_fp(suite, event_exec_mode_tip_pge, dfix_event, pt_ipc_full, + 0x1000); + ptu_run_f(suite, event_exec_mode_tip_pge_cutoff_fail, dfix_event); + ptu_run_f(suite, event_exec_mode_cutoff_fail, dfix_event); + ptu_run_fp(suite, event_tsx_fup, dfix_event, pt_ipc_suppressed, 0, + 0x1000); + ptu_run_fp(suite, event_tsx_fup, dfix_event, pt_ipc_update_16, + pt_mob_tsx_intx, 0x1000); + ptu_run_fp(suite, event_tsx_fup, dfix_event, pt_ipc_update_32, 0, + 0x1000); + ptu_run_fp(suite, event_tsx_fup, dfix_event, pt_ipc_update_48, 0, + 0x1000); + ptu_run_fp(suite, event_tsx_fup, dfix_event, pt_ipc_sext_48, + pt_mob_tsx_intx, 0x1000); + ptu_run_fp(suite, event_tsx_fup, dfix_event, pt_ipc_full, + pt_mob_tsx_intx, 0x1000); + ptu_run_f(suite, event_tsx_fup_cutoff_fail, dfix_event); + ptu_run_f(suite, event_tsx_cutoff_fail, dfix_event); + ptu_run_f(suite, event_skip_tip_fail, dfix_event); + ptu_run_f(suite, event_skip_tnt_8_fail, dfix_event); + ptu_run_f(suite, event_skip_tnt_64_fail, dfix_event); + ptu_run_fp(suite, sync_event, dfix_event, pt_ipc_suppressed); + ptu_run_fp(suite, sync_event, dfix_event, pt_ipc_update_16); + ptu_run_fp(suite, sync_event, dfix_event, pt_ipc_update_32); + ptu_run_fp(suite, sync_event, dfix_event, pt_ipc_update_48); + ptu_run_fp(suite, sync_event, dfix_event, pt_ipc_sext_48); + ptu_run_fp(suite, sync_event, dfix_event, pt_ipc_full); + ptu_run_f(suite, sync_event_cutoff_fail, dfix_event); + ptu_run_f(suite, sync_event_incomplete_fail, dfix_event); + ptu_run_fp(suite, sync_ovf_event, dfix_event, pt_ipc_suppressed); + ptu_run_fp(suite, sync_ovf_event, dfix_event, pt_ipc_update_16); + ptu_run_fp(suite, sync_ovf_event, dfix_event, pt_ipc_update_32); + ptu_run_fp(suite, sync_ovf_event, dfix_event, pt_ipc_update_48); + ptu_run_fp(suite, sync_ovf_event, dfix_event, pt_ipc_sext_48); + ptu_run_fp(suite, sync_ovf_event, dfix_event, pt_ipc_full); + ptu_run_f(suite, sync_ovf_event_cutoff_fail, dfix_event); + + ptu_run_fp(suite, event_enabled, dfix_event_psb, pt_ipc_suppressed, + 0x1000); + ptu_run_fp(suite, event_enabled, dfix_event_psb, pt_ipc_sext_48, + 0x1000); + ptu_run_fp(suite, event_enabled, dfix_event_psb, pt_ipc_full, + 0x1000); + ptu_run_f(suite, event_enabled_cutoff_fail, dfix_event_psb); + ptu_run_fp(suite, event_disabled, dfix_event_psb, pt_ipc_suppressed, + 0x1000); + ptu_run_fp(suite, event_disabled, dfix_event_psb, pt_ipc_sext_48, + 0x1000); + ptu_run_fp(suite, event_disabled, dfix_event_psb, pt_ipc_full, + 0x1000); + ptu_run_f(suite, event_disabled_cutoff_fail, dfix_event_psb); + ptu_run_fp(suite, event_async_disabled, dfix_event_psb, + pt_ipc_suppressed, 0x1000); + ptu_run_fp(suite, event_async_disabled, dfix_event_psb, + pt_ipc_update_16, 0x1000); + ptu_run_fp(suite, event_async_disabled, dfix_event_psb, + pt_ipc_update_32, 0x1000); + ptu_run_fp(suite, event_async_disabled, dfix_event_psb, + pt_ipc_update_48, 0x1000); + ptu_run_fp(suite, event_async_disabled, dfix_event_psb, + pt_ipc_sext_48, 0x1000); + ptu_run_fp(suite, event_async_disabled, dfix_event_psb, + pt_ipc_full, 0x1000); + ptu_run_f(suite, event_async_disabled_suppressed_fail, dfix_event_psb); + ptu_run_f(suite, event_async_disabled_cutoff_fail_a, dfix_event_psb); + ptu_run_f(suite, event_async_disabled_cutoff_fail_b, dfix_event_psb); + ptu_run_fp(suite, event_async_branch, dfix_event_psb, + pt_ipc_suppressed, 0x1000); + ptu_run_fp(suite, event_async_branch, dfix_event_psb, pt_ipc_update_16, + 0x1000); + ptu_run_fp(suite, event_async_branch, dfix_event_psb, pt_ipc_update_32, + 0x1000); + ptu_run_fp(suite, event_async_branch, dfix_event_psb, pt_ipc_update_48, + 0x1000); + ptu_run_fp(suite, event_async_branch, dfix_event_psb, pt_ipc_sext_48, + 0x1000); + ptu_run_fp(suite, event_async_branch, dfix_event_psb, pt_ipc_full, + 0x1000); + ptu_run_f(suite, event_async_branch_suppressed_fail, dfix_event_psb); + ptu_run_f(suite, event_async_branch_cutoff_fail_a, dfix_event_psb); + ptu_run_f(suite, event_async_branch_cutoff_fail_b, dfix_event_psb); + ptu_run_fp(suite, event_paging, dfix_event_psb, 0, 0x1000); + ptu_run_fp(suite, event_paging, dfix_event_psb, pt_pl_pip_nr, 0x1000); + ptu_run_f(suite, event_paging_cutoff_fail, dfix_event_psb); + ptu_run_fp(suite, event_async_paging, dfix_event_psb, 0, 0x1000); + ptu_run_fp(suite, event_async_paging, dfix_event_psb, pt_pl_pip_nr, + 0x1000); + ptu_run_fp(suite, event_async_paging_suppressed, dfix_event_psb, 0, + 0x1000); + ptu_run_fp(suite, event_async_paging_suppressed, dfix_event_psb, + pt_pl_pip_nr, 0x1000); + ptu_run_f(suite, event_async_paging_cutoff_fail, dfix_event_psb); + ptu_run_f(suite, event_overflow_cutoff_fail, dfix_event_psb); + ptu_run_fp(suite, event_stop, dfix_event_psb, 0x1000); + ptu_run_fp(suite, event_exec_mode_tip, dfix_event_psb, + pt_ipc_suppressed, 0x1000); + ptu_run_fp(suite, event_exec_mode_tip, dfix_event_psb, pt_ipc_sext_48, + 0x1000); + ptu_run_fp(suite, event_exec_mode_tip, dfix_event_psb, pt_ipc_full, + 0x1000); + ptu_run_f(suite, event_exec_mode_tip_cutoff_fail, dfix_event_psb); + ptu_run_fp(suite, event_exec_mode_tip_pge, dfix_event_psb, + pt_ipc_sext_48, 0x1000); + ptu_run_fp(suite, event_exec_mode_tip_pge, dfix_event_psb, + pt_ipc_full, 0x1000); + ptu_run_f(suite, event_exec_mode_tip_pge_cutoff_fail, dfix_event_psb); + ptu_run_f(suite, event_exec_mode_cutoff_fail, dfix_event_psb); + ptu_run_fp(suite, event_tsx_fup, dfix_event_psb, pt_ipc_suppressed, 0, + 0x1000); + ptu_run_fp(suite, event_tsx_fup, dfix_event_psb, pt_ipc_sext_48, + pt_mob_tsx_intx, 0x1000); + ptu_run_fp(suite, event_tsx_fup, dfix_event_psb, pt_ipc_full, + pt_mob_tsx_intx, 0x1000); + ptu_run_f(suite, event_tsx_fup_cutoff_fail, dfix_event_psb); + ptu_run_f(suite, event_tsx_cutoff_fail, dfix_event_psb); + ptu_run_f(suite, event_skip_tip_fail, dfix_event_psb); + ptu_run_f(suite, event_skip_tnt_8_fail, dfix_event_psb); + ptu_run_f(suite, event_skip_tnt_64_fail, dfix_event_psb); + + ptu_run_f(suite, time_null_fail, dfix_empty); + ptu_run_f(suite, time_initial, dfix_empty); + ptu_run_f(suite, time, dfix_empty); + + ptu_run_f(suite, cbr_null, dfix_empty); + ptu_run_f(suite, cbr_initial, dfix_empty); + ptu_run_f(suite, cbr, dfix_empty); + + ptu_run_f(suite, indir_cyc_cutoff, dfix_empty); + ptu_run_f(suite, cond_cyc_cutoff, dfix_empty); + ptu_run_f(suite, event_cyc_cutoff, dfix_empty); + + return ptunit_report(&suite); +} diff --git a/libipt/test/src/ptunit-retstack.c b/libipt/test/src/ptunit-retstack.c new file mode 100644 index 0000000000000..4386601df73ed --- /dev/null +++ b/libipt/test/src/ptunit-retstack.c @@ -0,0 +1,232 @@ +/* + * Copyright (c) 2013-2019, Intel Corporation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of Intel Corporation nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "ptunit.h" + +#include "pt_retstack.h" + +#include "intel-pt.h" + + +static struct ptunit_result init(void) +{ + struct pt_retstack retstack; + int status; + + memset(&retstack, 0xcd, sizeof(retstack)); + + pt_retstack_init(&retstack); + + status = pt_retstack_is_empty(&retstack); + ptu_int_ne(status, 0); + + return ptu_passed(); +} + +static struct ptunit_result init_null(void) +{ + pt_retstack_init(NULL); + + return ptu_passed(); +} + +static struct ptunit_result query(void) +{ + struct pt_retstack retstack; + uint64_t ip; + int status; + + pt_retstack_init(&retstack); + + status = pt_retstack_push(&retstack, 0x42ull); + ptu_int_eq(status, 0); + + status = pt_retstack_is_empty(&retstack); + ptu_int_eq(status, 0); + + status = pt_retstack_pop(&retstack, &ip); + ptu_int_eq(status, 0); + ptu_uint_eq(ip, 0x42ull); + + status = pt_retstack_is_empty(&retstack); + ptu_int_ne(status, 0); + + return ptu_passed(); +} + +static struct ptunit_result query_empty(void) +{ + struct pt_retstack retstack; + uint64_t ip; + int status; + + pt_retstack_init(&retstack); + + ip = 0x42ull; + status = pt_retstack_pop(&retstack, &ip); + ptu_int_eq(status, -pte_retstack_empty); + ptu_uint_eq(ip, 0x42ull); + + return ptu_passed(); +} + +static struct ptunit_result query_null(void) +{ + uint64_t ip; + int status; + + ip = 0x42ull; + status = pt_retstack_pop(NULL, &ip); + ptu_int_eq(status, -pte_invalid); + ptu_uint_eq(ip, 0x42ull); + + return ptu_passed(); +} + +static struct ptunit_result pop(void) +{ + struct pt_retstack retstack; + int status; + + pt_retstack_init(&retstack); + + status = pt_retstack_push(&retstack, 0x42ull); + ptu_int_eq(status, 0); + + status = pt_retstack_is_empty(&retstack); + ptu_int_eq(status, 0); + + status = pt_retstack_pop(&retstack, NULL); + ptu_int_eq(status, 0); + + status = pt_retstack_is_empty(&retstack); + ptu_int_ne(status, 0); + + return ptu_passed(); +} + +static struct ptunit_result pop_empty(void) +{ + struct pt_retstack retstack; + int status; + + pt_retstack_init(&retstack); + + status = pt_retstack_pop(&retstack, NULL); + ptu_int_eq(status, -pte_retstack_empty); + + return ptu_passed(); +} + +static struct ptunit_result pop_null(void) +{ + int status; + + status = pt_retstack_pop(NULL, NULL); + ptu_int_eq(status, -pte_invalid); + + return ptu_passed(); +} + +static struct ptunit_result full(void) +{ + struct pt_retstack retstack; + uint64_t ip, idx; + int status; + + pt_retstack_init(&retstack); + + for (idx = 0; idx < pt_retstack_size; ++idx) { + status = pt_retstack_push(&retstack, idx); + ptu_int_eq(status, 0); + } + + status = pt_retstack_is_empty(&retstack); + ptu_int_eq(status, 0); + + for (idx = pt_retstack_size; idx > 0;) { + idx -= 1; + + status = pt_retstack_pop(&retstack, &ip); + ptu_int_eq(status, 0); + ptu_uint_eq(ip, idx); + } + + status = pt_retstack_is_empty(&retstack); + ptu_int_ne(status, 0); + + return ptu_passed(); +} + +static struct ptunit_result overflow(void) +{ + struct pt_retstack retstack; + uint64_t ip, idx; + int status; + + pt_retstack_init(&retstack); + + for (idx = 0; idx <= pt_retstack_size; ++idx) { + status = pt_retstack_push(&retstack, idx); + ptu_int_eq(status, 0); + } + + status = pt_retstack_is_empty(&retstack); + ptu_int_eq(status, 0); + + for (idx = pt_retstack_size; idx > 0; --idx) { + status = pt_retstack_pop(&retstack, &ip); + ptu_int_eq(status, 0); + ptu_uint_eq(ip, idx); + } + + status = pt_retstack_is_empty(&retstack); + ptu_int_ne(status, 0); + + return ptu_passed(); +} + +int main(int argc, char **argv) +{ + struct ptunit_suite suite; + + suite = ptunit_mk_suite(argc, argv); + + ptu_run(suite, init); + ptu_run(suite, init_null); + ptu_run(suite, query); + ptu_run(suite, query_empty); + ptu_run(suite, query_null); + ptu_run(suite, pop); + ptu_run(suite, pop_empty); + ptu_run(suite, pop_null); + ptu_run(suite, full); + ptu_run(suite, overflow); + + return ptunit_report(&suite); +} diff --git a/libipt/test/src/ptunit-section-file.c b/libipt/test/src/ptunit-section-file.c new file mode 100644 index 0000000000000..9e04ccbfbc07b --- /dev/null +++ b/libipt/test/src/ptunit-section-file.c @@ -0,0 +1,192 @@ +/* + * Copyright (c) 2015-2019, Intel Corporation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of Intel Corporation nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "pt_section.h" +#include "pt_section_file.h" + +#include "intel-pt.h" + +#include <stdlib.h> +#include <stdio.h> + + +/* This is a variation of ptunit-section.c. + * + * We provide pt_section_map() et.al. that are normally provided by mmap-based + * section implementations. Our implementation falls back to file-based + * sections so we're able to test them. + * + * The actual test is in ptunit-section.c. + */ + +/* The file status used for detecting changes to a file between unmap and map. + * + * In our case, the changes always affect the size of the file. + */ +struct pt_file_status { + /* The size in bytes. */ + long size; +}; + +int pt_section_mk_status(void **pstatus, uint64_t *psize, const char *filename) +{ + struct pt_file_status *status; + FILE *file; + long size; + int errcode; + + if (!pstatus || !psize) + return -pte_internal; + + file = fopen(filename, "rb"); + if (!file) + return -pte_bad_image; + + errcode = fseek(file, 0, SEEK_END); + if (errcode) { + errcode = -pte_bad_image; + goto out_file; + } + + size = ftell(file); + if (size < 0) { + errcode = -pte_bad_image; + goto out_file; + } + + status = malloc(sizeof(*status)); + if (!status) { + errcode = -pte_nomem; + goto out_file; + } + + status->size = size; + + *pstatus = status; + *psize = (uint64_t) size; + + errcode = 0; + +out_file: + fclose(file); + return errcode; +} + +static int pt_section_map_success(struct pt_section *section) +{ + uint16_t mcount; + int errcode, status; + + if (!section) + return -pte_internal; + + mcount = section->mcount + 1; + if (!mcount) { + (void) pt_section_unlock(section); + return -pte_overflow; + } + + section->mcount = mcount; + + errcode = pt_section_unlock(section); + if (errcode < 0) + return errcode; + + status = pt_section_on_map(section); + if (status < 0) { + (void) pt_section_unmap(section); + return status; + } + + return 0; +} + +int pt_section_map(struct pt_section *section) +{ + struct pt_file_status *status; + const char *filename; + uint16_t mcount; + FILE *file; + long size; + int errcode; + + if (!section) + return -pte_internal; + + errcode = pt_section_lock(section); + if (errcode < 0) + return errcode; + + mcount = section->mcount; + if (mcount) + return pt_section_map_success(section); + + if (section->mapping) + goto out_unlock; + + filename = section->filename; + if (!filename) + goto out_unlock; + + status = section->status; + if (!status) + goto out_unlock; + + errcode = -pte_bad_image; + file = fopen(filename, "rb"); + if (!file) + goto out_unlock; + + errcode = fseek(file, 0, SEEK_END); + if (errcode) { + errcode = -pte_bad_image; + goto out_file; + } + + errcode = -pte_bad_image; + size = ftell(file); + if (size < 0) + goto out_file; + + if (size != status->size) + goto out_file; + + /* We need to keep the file open on success. It will be closed when + * the section is unmapped. + */ + errcode = pt_sec_file_map(section, file); + if (!errcode) + return pt_section_map_success(section); + +out_file: + fclose(file); + +out_unlock: + (void) pt_section_unlock(section); + return errcode; +} diff --git a/libipt/test/src/ptunit-section.c b/libipt/test/src/ptunit-section.c new file mode 100644 index 0000000000000..6b752c00b90c2 --- /dev/null +++ b/libipt/test/src/ptunit-section.c @@ -0,0 +1,1463 @@ +/* + * Copyright (c) 2013-2019, Intel Corporation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of Intel Corporation nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "ptunit_threads.h" +#include "ptunit_mkfile.h" + +#include "pt_section.h" +#include "pt_block_cache.h" + +#include "intel-pt.h" + +#include <stdlib.h> +#include <stdio.h> + + + +struct pt_image_section_cache { + int map; +}; + +extern int pt_iscache_notify_map(struct pt_image_section_cache *iscache, + struct pt_section *section); +extern int pt_iscache_notify_resize(struct pt_image_section_cache *iscache, + struct pt_section *section, uint64_t size); + +int pt_iscache_notify_map(struct pt_image_section_cache *iscache, + struct pt_section *section) +{ + if (!iscache) + return -pte_internal; + + if (iscache->map <= 0) + return iscache->map; + + /* Avoid recursion. */ + iscache->map = 0; + + return pt_section_map_share(section); +} + +int pt_iscache_notify_resize(struct pt_image_section_cache *iscache, + struct pt_section *section, uint64_t size) +{ + uint64_t memsize; + int errcode; + + if (!iscache) + return -pte_internal; + + if (iscache->map <= 0) + return iscache->map; + + /* Avoid recursion. */ + iscache->map = 0; + + errcode = pt_section_memsize(section, &memsize); + if (errcode < 0) + return errcode; + + if (size != memsize) + return -pte_internal; + + return pt_section_map_share(section); +} + +struct pt_block_cache *pt_bcache_alloc(uint64_t nentries) +{ + struct pt_block_cache *bcache; + + if (!nentries || (UINT32_MAX < nentries)) + return NULL; + + /* The cache is not really used by tests. It suffices to allocate only + * the cache struct with the single default entry. + * + * We still set the number of entries to the requested size. + */ + bcache = malloc(sizeof(*bcache)); + if (bcache) + bcache->nentries = (uint32_t) nentries; + + return bcache; +} + +void pt_bcache_free(struct pt_block_cache *bcache) +{ + free(bcache); +} + +/* A test fixture providing a temporary file and an initially NULL section. */ +struct section_fixture { + /* Threading support. */ + struct ptunit_thrd_fixture thrd; + + /* A temporary file name. */ + char *name; + + /* That file opened for writing. */ + FILE *file; + + /* The section. */ + struct pt_section *section; + + /* The test fixture initialization and finalization functions. */ + struct ptunit_result (*init)(struct section_fixture *); + struct ptunit_result (*fini)(struct section_fixture *); +}; + +enum { +#if defined(FEATURE_THREADS) + + num_threads = 4, + +#endif /* defined(FEATURE_THREADS) */ + + num_work = 0x4000 +}; + +static struct ptunit_result sfix_write_aux(struct section_fixture *sfix, + const uint8_t *buffer, size_t size) +{ + size_t written; + + written = fwrite(buffer, 1, size, sfix->file); + ptu_uint_eq(written, size); + + fflush(sfix->file); + + return ptu_passed(); +} + +#define sfix_write(sfix, buffer) \ + ptu_check(sfix_write_aux, sfix, buffer, sizeof(buffer)) + +static struct ptunit_result create(struct section_fixture *sfix) +{ + const char *name; + uint8_t bytes[] = { 0xcc, 0xcc, 0xcc, 0xcc, 0xcc }; + uint64_t offset, size; + int errcode; + + sfix_write(sfix, bytes); + + errcode = pt_mk_section(&sfix->section, sfix->name, 0x1ull, 0x3ull); + ptu_int_eq(errcode, 0); + ptu_ptr(sfix->section); + + name = pt_section_filename(sfix->section); + ptu_str_eq(name, sfix->name); + + offset = pt_section_offset(sfix->section); + ptu_uint_eq(offset, 0x1ull); + + size = pt_section_size(sfix->section); + ptu_uint_eq(size, 0x3ull); + + return ptu_passed(); +} + +static struct ptunit_result create_bad_offset(struct section_fixture *sfix) +{ + int errcode; + + errcode = pt_mk_section(&sfix->section, sfix->name, 0x10ull, 0x0ull); + ptu_int_eq(errcode, -pte_invalid); + + return ptu_passed(); +} + +static struct ptunit_result create_truncated(struct section_fixture *sfix) +{ + const char *name; + uint8_t bytes[] = { 0xcc, 0xcc, 0xcc, 0xcc, 0xcc }; + uint64_t offset, size; + int errcode; + + sfix_write(sfix, bytes); + + errcode = pt_mk_section(&sfix->section, sfix->name, 0x1ull, UINT64_MAX); + ptu_int_eq(errcode, 0); + ptu_ptr(sfix->section); + + name = pt_section_filename(sfix->section); + ptu_str_eq(name, sfix->name); + + offset = pt_section_offset(sfix->section); + ptu_uint_eq(offset, 0x1ull); + + size = pt_section_size(sfix->section); + ptu_uint_eq(size, sizeof(bytes) - 1); + + return ptu_passed(); +} + +static struct ptunit_result create_empty(struct section_fixture *sfix) +{ + int errcode; + + errcode = pt_mk_section(&sfix->section, sfix->name, 0x0ull, 0x10ull); + ptu_int_eq(errcode, -pte_invalid); + ptu_null(sfix->section); + + return ptu_passed(); +} + +static struct ptunit_result filename_null(void) +{ + const char *name; + + name = pt_section_filename(NULL); + ptu_null(name); + + return ptu_passed(); +} + +static struct ptunit_result size_null(void) +{ + uint64_t size; + + size = pt_section_size(NULL); + ptu_uint_eq(size, 0ull); + + return ptu_passed(); +} + +static struct ptunit_result memsize_null(struct section_fixture *sfix) +{ + uint64_t size; + int errcode; + + errcode = pt_section_memsize(NULL, &size); + ptu_int_eq(errcode, -pte_internal); + + errcode = pt_section_memsize(sfix->section, NULL); + ptu_int_eq(errcode, -pte_internal); + + errcode = pt_section_memsize(NULL, NULL); + ptu_int_eq(errcode, -pte_internal); + + return ptu_passed(); +} + +static struct ptunit_result offset_null(void) +{ + uint64_t offset; + + offset = pt_section_offset(NULL); + ptu_uint_eq(offset, 0ull); + + return ptu_passed(); +} + +static struct ptunit_result get_null(void) +{ + int errcode; + + errcode = pt_section_get(NULL); + ptu_int_eq(errcode, -pte_internal); + + return ptu_passed(); +} + +static struct ptunit_result put_null(void) +{ + int errcode; + + errcode = pt_section_put(NULL); + ptu_int_eq(errcode, -pte_internal); + + return ptu_passed(); +} + +static struct ptunit_result attach_null(void) +{ + struct pt_image_section_cache iscache; + struct pt_section section; + int errcode; + + errcode = pt_section_attach(NULL, &iscache); + ptu_int_eq(errcode, -pte_internal); + + errcode = pt_section_attach(§ion, NULL); + ptu_int_eq(errcode, -pte_internal); + + errcode = pt_section_attach(NULL, NULL); + ptu_int_eq(errcode, -pte_internal); + + return ptu_passed(); +} + +static struct ptunit_result detach_null(void) +{ + struct pt_image_section_cache iscache; + struct pt_section section; + int errcode; + + errcode = pt_section_detach(NULL, &iscache); + ptu_int_eq(errcode, -pte_internal); + + errcode = pt_section_detach(§ion, NULL); + ptu_int_eq(errcode, -pte_internal); + + errcode = pt_section_detach(NULL, NULL); + ptu_int_eq(errcode, -pte_internal); + + return ptu_passed(); +} + +static struct ptunit_result map_null(void) +{ + int errcode; + + errcode = pt_section_map(NULL); + ptu_int_eq(errcode, -pte_internal); + + return ptu_passed(); +} + +static struct ptunit_result unmap_null(void) +{ + int errcode; + + errcode = pt_section_unmap(NULL); + ptu_int_eq(errcode, -pte_internal); + + return ptu_passed(); +} + +static struct ptunit_result cache_null(void) +{ + struct pt_block_cache *bcache; + + bcache = pt_section_bcache(NULL); + ptu_null(bcache); + + return ptu_passed(); +} + +static struct ptunit_result get_overflow(struct section_fixture *sfix) +{ + uint8_t bytes[] = { 0xcc, 0x2, 0x4, 0x6 }; + int errcode; + + sfix_write(sfix, bytes); + + errcode = pt_mk_section(&sfix->section, sfix->name, 0x1ull, 0x3ull); + ptu_int_eq(errcode, 0); + ptu_ptr(sfix->section); + + sfix->section->ucount = UINT16_MAX; + + errcode = pt_section_get(sfix->section); + ptu_int_eq(errcode, -pte_overflow); + + sfix->section->ucount = 1; + + return ptu_passed(); +} + +static struct ptunit_result attach_overflow(struct section_fixture *sfix) +{ + struct pt_image_section_cache iscache; + uint8_t bytes[] = { 0xcc, 0x2, 0x4, 0x6 }; + int errcode; + + sfix_write(sfix, bytes); + + errcode = pt_mk_section(&sfix->section, sfix->name, 0x1ull, 0x3ull); + ptu_int_eq(errcode, 0); + ptu_ptr(sfix->section); + + sfix->section->acount = UINT16_MAX; + + errcode = pt_section_attach(sfix->section, &iscache); + ptu_int_eq(errcode, -pte_overflow); + + sfix->section->acount = 0; + + return ptu_passed(); +} + +static struct ptunit_result attach_bad_ucount(struct section_fixture *sfix) +{ + struct pt_image_section_cache iscache; + uint8_t bytes[] = { 0xcc, 0x2, 0x4, 0x6 }; + int errcode; + + sfix_write(sfix, bytes); + + errcode = pt_mk_section(&sfix->section, sfix->name, 0x1ull, 0x3ull); + ptu_int_eq(errcode, 0); + ptu_ptr(sfix->section); + + sfix->section->acount = 2; + + errcode = pt_section_attach(sfix->section, &iscache); + ptu_int_eq(errcode, -pte_internal); + + sfix->section->acount = 0; + + return ptu_passed(); +} + +static struct ptunit_result map_change(struct section_fixture *sfix) +{ + uint8_t bytes[] = { 0xcc, 0x2, 0x4, 0x6 }; + int errcode; + + sfix_write(sfix, bytes); + + errcode = pt_mk_section(&sfix->section, sfix->name, 0x1ull, 0x3ull); + ptu_int_eq(errcode, 0); + ptu_ptr(sfix->section); + + sfix_write(sfix, bytes); + + errcode = pt_section_map(sfix->section); + ptu_int_eq(errcode, -pte_bad_image); + + return ptu_passed(); +} + +static struct ptunit_result map_put(struct section_fixture *sfix) +{ + uint8_t bytes[] = { 0xcc, 0x2, 0x4, 0x6 }; + int errcode; + + sfix_write(sfix, bytes); + + errcode = pt_mk_section(&sfix->section, sfix->name, 0x1ull, 0x3ull); + ptu_int_eq(errcode, 0); + ptu_ptr(sfix->section); + + errcode = pt_section_map(sfix->section); + ptu_int_eq(errcode, 0); + + errcode = pt_section_put(sfix->section); + ptu_int_eq(errcode, -pte_internal); + + errcode = pt_section_unmap(sfix->section); + ptu_int_eq(errcode, 0); + + return ptu_passed(); +} + +static struct ptunit_result unmap_nomap(struct section_fixture *sfix) +{ + uint8_t bytes[] = { 0xcc, 0x2, 0x4, 0x6 }; + int errcode; + + sfix_write(sfix, bytes); + + errcode = pt_mk_section(&sfix->section, sfix->name, 0x1ull, 0x3ull); + ptu_int_eq(errcode, 0); + ptu_ptr(sfix->section); + + errcode = pt_section_unmap(sfix->section); + ptu_int_eq(errcode, -pte_nomap); + + return ptu_passed(); +} + +static struct ptunit_result map_overflow(struct section_fixture *sfix) +{ + uint8_t bytes[] = { 0xcc, 0x2, 0x4, 0x6 }; + int errcode; + + sfix_write(sfix, bytes); + + errcode = pt_mk_section(&sfix->section, sfix->name, 0x1ull, 0x3ull); + ptu_int_eq(errcode, 0); + ptu_ptr(sfix->section); + + sfix->section->mcount = UINT16_MAX; + + errcode = pt_section_map(sfix->section); + ptu_int_eq(errcode, -pte_overflow); + + sfix->section->mcount = 0; + + return ptu_passed(); +} + +static struct ptunit_result get_put(struct section_fixture *sfix) +{ + uint8_t bytes[] = { 0xcc, 0x2, 0x4, 0x6 }; + int errcode; + + sfix_write(sfix, bytes); + + errcode = pt_mk_section(&sfix->section, sfix->name, 0x1ull, 0x3ull); + ptu_int_eq(errcode, 0); + ptu_ptr(sfix->section); + + errcode = pt_section_get(sfix->section); + ptu_int_eq(errcode, 0); + + errcode = pt_section_get(sfix->section); + ptu_int_eq(errcode, 0); + + errcode = pt_section_put(sfix->section); + ptu_int_eq(errcode, 0); + + errcode = pt_section_put(sfix->section); + ptu_int_eq(errcode, 0); + + return ptu_passed(); +} + +static struct ptunit_result attach_detach(struct section_fixture *sfix) +{ + struct pt_image_section_cache iscache; + uint8_t bytes[] = { 0xcc, 0x2, 0x4, 0x6 }; + int errcode; + + sfix_write(sfix, bytes); + + errcode = pt_mk_section(&sfix->section, sfix->name, 0x1ull, 0x3ull); + ptu_int_eq(errcode, 0); + ptu_ptr(sfix->section); + + sfix->section->ucount += 2; + + errcode = pt_section_attach(sfix->section, &iscache); + ptu_int_eq(errcode, 0); + + errcode = pt_section_attach(sfix->section, &iscache); + ptu_int_eq(errcode, 0); + + errcode = pt_section_detach(sfix->section, &iscache); + ptu_int_eq(errcode, 0); + + errcode = pt_section_detach(sfix->section, &iscache); + ptu_int_eq(errcode, 0); + + sfix->section->ucount -= 2; + + return ptu_passed(); +} + +static struct ptunit_result attach_bad_iscache(struct section_fixture *sfix) +{ + struct pt_image_section_cache iscache, bad; + uint8_t bytes[] = { 0xcc, 0x2, 0x4, 0x6 }; + int errcode; + + sfix_write(sfix, bytes); + + errcode = pt_mk_section(&sfix->section, sfix->name, 0x1ull, 0x3ull); + ptu_int_eq(errcode, 0); + ptu_ptr(sfix->section); + + sfix->section->ucount += 2; + + errcode = pt_section_attach(sfix->section, &iscache); + ptu_int_eq(errcode, 0); + + errcode = pt_section_attach(sfix->section, &bad); + ptu_int_eq(errcode, -pte_internal); + + errcode = pt_section_detach(sfix->section, &iscache); + ptu_int_eq(errcode, 0); + + sfix->section->ucount -= 2; + + return ptu_passed(); +} + +static struct ptunit_result detach_bad_iscache(struct section_fixture *sfix) +{ + struct pt_image_section_cache iscache, bad; + uint8_t bytes[] = { 0xcc, 0x2, 0x4, 0x6 }; + int errcode; + + sfix_write(sfix, bytes); + + errcode = pt_mk_section(&sfix->section, sfix->name, 0x1ull, 0x3ull); + ptu_int_eq(errcode, 0); + ptu_ptr(sfix->section); + + errcode = pt_section_attach(sfix->section, &iscache); + ptu_int_eq(errcode, 0); + + errcode = pt_section_detach(sfix->section, &bad); + ptu_int_eq(errcode, -pte_internal); + + errcode = pt_section_detach(sfix->section, &iscache); + ptu_int_eq(errcode, 0); + + return ptu_passed(); +} + +static struct ptunit_result map_unmap(struct section_fixture *sfix) +{ + uint8_t bytes[] = { 0xcc, 0x2, 0x4, 0x6 }; + int errcode; + + sfix_write(sfix, bytes); + + errcode = pt_mk_section(&sfix->section, sfix->name, 0x1ull, 0x3ull); + ptu_int_eq(errcode, 0); + ptu_ptr(sfix->section); + + errcode = pt_section_map(sfix->section); + ptu_int_eq(errcode, 0); + + errcode = pt_section_map(sfix->section); + ptu_int_eq(errcode, 0); + + errcode = pt_section_unmap(sfix->section); + ptu_int_eq(errcode, 0); + + errcode = pt_section_unmap(sfix->section); + ptu_int_eq(errcode, 0); + + return ptu_passed(); +} + +static struct ptunit_result attach_map(struct section_fixture *sfix) +{ + struct pt_image_section_cache iscache; + uint8_t bytes[] = { 0xcc, 0x2, 0x4, 0x6 }; + int errcode; + + iscache.map = 0; + + sfix_write(sfix, bytes); + + errcode = pt_mk_section(&sfix->section, sfix->name, 0x1ull, 0x3ull); + ptu_int_eq(errcode, 0); + ptu_ptr(sfix->section); + + errcode = pt_section_attach(sfix->section, &iscache); + ptu_int_eq(errcode, 0); + + errcode = pt_section_map(sfix->section); + ptu_int_eq(errcode, 0); + + errcode = pt_section_map(sfix->section); + ptu_int_eq(errcode, 0); + + ptu_uint_eq(sfix->section->mcount, 2); + + errcode = pt_section_unmap(sfix->section); + ptu_int_eq(errcode, 0); + + errcode = pt_section_unmap(sfix->section); + ptu_int_eq(errcode, 0); + + errcode = pt_section_detach(sfix->section, &iscache); + ptu_int_eq(errcode, 0); + + return ptu_passed(); +} + +static struct ptunit_result attach_bad_map(struct section_fixture *sfix) +{ + struct pt_image_section_cache iscache; + uint8_t bytes[] = { 0xcc, 0x2, 0x4, 0x6 }; + int errcode; + + iscache.map = -pte_eos; + + sfix_write(sfix, bytes); + + errcode = pt_mk_section(&sfix->section, sfix->name, 0x1ull, 0x3ull); + ptu_int_eq(errcode, 0); + ptu_ptr(sfix->section); + + errcode = pt_section_attach(sfix->section, &iscache); + ptu_int_eq(errcode, 0); + + errcode = pt_section_map(sfix->section); + ptu_int_eq(errcode, -pte_eos); + + errcode = pt_section_detach(sfix->section, &iscache); + ptu_int_eq(errcode, 0); + + return ptu_passed(); +} + +static struct ptunit_result attach_map_overflow(struct section_fixture *sfix) +{ + struct pt_image_section_cache iscache; + uint8_t bytes[] = { 0xcc, 0x2, 0x4, 0x6 }; + int errcode; + + iscache.map = 1; + + sfix_write(sfix, bytes); + + errcode = pt_mk_section(&sfix->section, sfix->name, 0x1ull, 0x3ull); + ptu_int_eq(errcode, 0); + ptu_ptr(sfix->section); + + errcode = pt_section_attach(sfix->section, &iscache); + ptu_int_eq(errcode, 0); + + sfix->section->mcount = UINT16_MAX - 1; + + errcode = pt_section_map(sfix->section); + ptu_int_eq(errcode, -pte_overflow); + + errcode = pt_section_detach(sfix->section, &iscache); + ptu_int_eq(errcode, 0); + + return ptu_passed(); +} + +static struct ptunit_result read(struct section_fixture *sfix) +{ + uint8_t bytes[] = { 0xcc, 0x2, 0x4, 0x6 }; + uint8_t buffer[] = { 0xcc, 0xcc, 0xcc }; + int status; + + sfix_write(sfix, bytes); + + status = pt_mk_section(&sfix->section, sfix->name, 0x1ull, 0x3ull); + ptu_int_eq(status, 0); + ptu_ptr(sfix->section); + + status = pt_section_map(sfix->section); + ptu_int_eq(status, 0); + + status = pt_section_read(sfix->section, buffer, 2, 0x0ull); + ptu_int_eq(status, 2); + ptu_uint_eq(buffer[0], bytes[1]); + ptu_uint_eq(buffer[1], bytes[2]); + ptu_uint_eq(buffer[2], 0xcc); + + status = pt_section_unmap(sfix->section); + ptu_int_eq(status, 0); + + return ptu_passed(); +} + +static struct ptunit_result read_null(struct section_fixture *sfix) +{ + uint8_t bytes[] = { 0xcc, 0x2, 0x4, 0x6 }; + uint8_t buffer[] = { 0xcc }; + int status; + + sfix_write(sfix, bytes); + + status = pt_mk_section(&sfix->section, sfix->name, 0x1ull, 0x3ull); + ptu_int_eq(status, 0); + ptu_ptr(sfix->section); + + status = pt_section_map(sfix->section); + ptu_int_eq(status, 0); + + status = pt_section_read(sfix->section, NULL, 1, 0x0ull); + ptu_int_eq(status, -pte_internal); + ptu_uint_eq(buffer[0], 0xcc); + + status = pt_section_read(NULL, buffer, 1, 0x0ull); + ptu_int_eq(status, -pte_internal); + ptu_uint_eq(buffer[0], 0xcc); + + status = pt_section_unmap(sfix->section); + ptu_int_eq(status, 0); + + return ptu_passed(); +} + +static struct ptunit_result read_offset(struct section_fixture *sfix) +{ + uint8_t bytes[] = { 0xcc, 0x2, 0x4, 0x6 }; + uint8_t buffer[] = { 0xcc, 0xcc, 0xcc }; + int status; + + sfix_write(sfix, bytes); + + status = pt_mk_section(&sfix->section, sfix->name, 0x1ull, 0x3ull); + ptu_int_eq(status, 0); + ptu_ptr(sfix->section); + + status = pt_section_map(sfix->section); + ptu_int_eq(status, 0); + + status = pt_section_read(sfix->section, buffer, 2, 0x1ull); + ptu_int_eq(status, 2); + ptu_uint_eq(buffer[0], bytes[2]); + ptu_uint_eq(buffer[1], bytes[3]); + ptu_uint_eq(buffer[2], 0xcc); + + status = pt_section_unmap(sfix->section); + ptu_int_eq(status, 0); + + return ptu_passed(); +} + +static struct ptunit_result read_truncated(struct section_fixture *sfix) +{ + uint8_t bytes[] = { 0xcc, 0x2, 0x4, 0x6 }, buffer[] = { 0xcc, 0xcc }; + int status; + + sfix_write(sfix, bytes); + + status = pt_mk_section(&sfix->section, sfix->name, 0x1ull, 0x3ull); + ptu_int_eq(status, 0); + ptu_ptr(sfix->section); + + status = pt_section_map(sfix->section); + ptu_int_eq(status, 0); + + status = pt_section_read(sfix->section, buffer, 2, 0x2ull); + ptu_int_eq(status, 1); + ptu_uint_eq(buffer[0], bytes[3]); + ptu_uint_eq(buffer[1], 0xcc); + + status = pt_section_unmap(sfix->section); + ptu_int_eq(status, 0); + + return ptu_passed(); +} + +static struct ptunit_result read_from_truncated(struct section_fixture *sfix) +{ + uint8_t bytes[] = { 0xcc, 0x2, 0x4, 0x6 }, buffer[] = { 0xcc, 0xcc }; + int status; + + sfix_write(sfix, bytes); + + status = pt_mk_section(&sfix->section, sfix->name, 0x2ull, 0x10ull); + ptu_int_eq(status, 0); + ptu_ptr(sfix->section); + + status = pt_section_map(sfix->section); + ptu_int_eq(status, 0); + + status = pt_section_read(sfix->section, buffer, 2, 0x1ull); + ptu_int_eq(status, 1); + ptu_uint_eq(buffer[0], bytes[3]); + ptu_uint_eq(buffer[1], 0xcc); + + status = pt_section_unmap(sfix->section); + ptu_int_eq(status, 0); + + return ptu_passed(); +} + +static struct ptunit_result read_nomem(struct section_fixture *sfix) +{ + uint8_t bytes[] = { 0xcc, 0x2, 0x4, 0x6 }, buffer[] = { 0xcc }; + int status; + + sfix_write(sfix, bytes); + + status = pt_mk_section(&sfix->section, sfix->name, 0x1ull, 0x3ull); + ptu_int_eq(status, 0); + ptu_ptr(sfix->section); + + status = pt_section_map(sfix->section); + ptu_int_eq(status, 0); + + status = pt_section_read(sfix->section, buffer, 1, 0x3ull); + ptu_int_eq(status, -pte_nomap); + ptu_uint_eq(buffer[0], 0xcc); + + status = pt_section_unmap(sfix->section); + ptu_int_eq(status, 0); + + return ptu_passed(); +} + +static struct ptunit_result read_overflow(struct section_fixture *sfix) +{ + uint8_t bytes[] = { 0xcc, 0x2, 0x4, 0x6 }, buffer[] = { 0xcc }; + int status; + + sfix_write(sfix, bytes); + + status = pt_mk_section(&sfix->section, sfix->name, 0x1ull, 0x3ull); + ptu_int_eq(status, 0); + ptu_ptr(sfix->section); + + status = pt_section_map(sfix->section); + ptu_int_eq(status, 0); + + status = pt_section_read(sfix->section, buffer, 1, + 0xffffffffffff0000ull); + ptu_int_eq(status, -pte_nomap); + ptu_uint_eq(buffer[0], 0xcc); + + status = pt_section_unmap(sfix->section); + ptu_int_eq(status, 0); + + return ptu_passed(); +} + +static struct ptunit_result read_overflow_32bit(struct section_fixture *sfix) +{ + uint8_t bytes[] = { 0xcc, 0x2, 0x4, 0x6 }, buffer[] = { 0xcc }; + int status; + + sfix_write(sfix, bytes); + + status = pt_mk_section(&sfix->section, sfix->name, 0x1ull, 0x3ull); + ptu_int_eq(status, 0); + ptu_ptr(sfix->section); + + status = pt_section_map(sfix->section); + ptu_int_eq(status, 0); + + status = pt_section_read(sfix->section, buffer, 1, + 0xff00000000ull); + ptu_int_eq(status, -pte_nomap); + ptu_uint_eq(buffer[0], 0xcc); + + status = pt_section_unmap(sfix->section); + ptu_int_eq(status, 0); + + return ptu_passed(); +} + +static struct ptunit_result read_nomap(struct section_fixture *sfix) +{ + uint8_t bytes[] = { 0xcc, 0x2, 0x4, 0x6 }, buffer[] = { 0xcc }; + int status; + + sfix_write(sfix, bytes); + + status = pt_mk_section(&sfix->section, sfix->name, 0x1ull, 0x3ull); + ptu_int_eq(status, 0); + ptu_ptr(sfix->section); + + status = pt_section_read(sfix->section, buffer, 1, 0x0ull); + ptu_int_eq(status, -pte_nomap); + ptu_uint_eq(buffer[0], 0xcc); + + return ptu_passed(); +} + +static struct ptunit_result read_unmap_map(struct section_fixture *sfix) +{ + uint8_t bytes[] = { 0xcc, 0x2, 0x4, 0x6 }; + uint8_t buffer[] = { 0xcc, 0xcc, 0xcc }; + int status; + + sfix_write(sfix, bytes); + + status = pt_mk_section(&sfix->section, sfix->name, 0x1ull, 0x3ull); + ptu_int_eq(status, 0); + ptu_ptr(sfix->section); + + status = pt_section_map(sfix->section); + ptu_int_eq(status, 0); + + status = pt_section_read(sfix->section, buffer, 2, 0x0ull); + ptu_int_eq(status, 2); + ptu_uint_eq(buffer[0], bytes[1]); + ptu_uint_eq(buffer[1], bytes[2]); + ptu_uint_eq(buffer[2], 0xcc); + + memset(buffer, 0xcc, sizeof(buffer)); + + status = pt_section_unmap(sfix->section); + ptu_int_eq(status, 0); + + status = pt_section_read(sfix->section, buffer, 2, 0x0ull); + ptu_int_eq(status, -pte_nomap); + ptu_uint_eq(buffer[0], 0xcc); + ptu_uint_eq(buffer[1], 0xcc); + ptu_uint_eq(buffer[2], 0xcc); + + status = pt_section_map(sfix->section); + ptu_int_eq(status, 0); + + status = pt_section_read(sfix->section, buffer, 2, 0x0ull); + ptu_int_eq(status, 2); + ptu_uint_eq(buffer[0], bytes[1]); + ptu_uint_eq(buffer[1], bytes[2]); + ptu_uint_eq(buffer[2], 0xcc); + + status = pt_section_unmap(sfix->section); + ptu_int_eq(status, 0); + + return ptu_passed(); +} + +static int worker_read(void *arg) +{ + struct section_fixture *sfix; + int it, errcode; + + sfix = arg; + if (!sfix) + return -pte_internal; + + for (it = 0; it < num_work; ++it) { + uint8_t buffer[] = { 0xcc, 0xcc, 0xcc }; + int read; + + errcode = pt_section_get(sfix->section); + if (errcode < 0) + return errcode; + + errcode = pt_section_map(sfix->section); + if (errcode < 0) + goto out_put; + + read = pt_section_read(sfix->section, buffer, 2, 0x0ull); + if (read < 0) + goto out_unmap; + + errcode = -pte_invalid; + if ((read != 2) || (buffer[0] != 0x2) || (buffer[1] != 0x4)) + goto out_unmap; + + errcode = pt_section_unmap(sfix->section); + if (errcode < 0) + goto out_put; + + errcode = pt_section_put(sfix->section); + if (errcode < 0) + return errcode; + } + + return 0; + +out_unmap: + (void) pt_section_unmap(sfix->section); + +out_put: + (void) pt_section_put(sfix->section); + return errcode; +} + +static int worker_bcache(void *arg) +{ + struct section_fixture *sfix; + int it, errcode; + + sfix = arg; + if (!sfix) + return -pte_internal; + + errcode = pt_section_get(sfix->section); + if (errcode < 0) + return errcode; + + for (it = 0; it < num_work; ++it) { + struct pt_block_cache *bcache; + + errcode = pt_section_map(sfix->section); + if (errcode < 0) + goto out_put; + + errcode = pt_section_request_bcache(sfix->section); + if (errcode < 0) + goto out_unmap; + + bcache = pt_section_bcache(sfix->section); + if (!bcache) { + errcode = -pte_nomem; + goto out_unmap; + } + + errcode = pt_section_unmap(sfix->section); + if (errcode < 0) + goto out_put; + } + + return pt_section_put(sfix->section); + +out_unmap: + (void) pt_section_unmap(sfix->section); + +out_put: + (void) pt_section_put(sfix->section); + return errcode; +} + +static struct ptunit_result stress(struct section_fixture *sfix, + int (*worker)(void *)) +{ + uint8_t bytes[] = { 0xcc, 0x2, 0x4, 0x6 }; + int errcode; + + sfix_write(sfix, bytes); + + errcode = pt_mk_section(&sfix->section, sfix->name, 0x1ull, 0x3ull); + ptu_int_eq(errcode, 0); + ptu_ptr(sfix->section); + +#if defined(FEATURE_THREADS) + { + int thrd; + + for (thrd = 0; thrd < num_threads; ++thrd) + ptu_test(ptunit_thrd_create, &sfix->thrd, worker, sfix); + } +#endif /* defined(FEATURE_THREADS) */ + + errcode = worker(sfix); + ptu_int_eq(errcode, 0); + + return ptu_passed(); +} + +static struct ptunit_result init_no_bcache(struct section_fixture *sfix) +{ + uint8_t bytes[] = { 0xcc, 0x2, 0x4, 0x6 }; + struct pt_block_cache *bcache; + int errcode; + + sfix_write(sfix, bytes); + + errcode = pt_mk_section(&sfix->section, sfix->name, 0x1ull, 0x3ull); + ptu_int_eq(errcode, 0); + ptu_ptr(sfix->section); + + errcode = pt_section_map(sfix->section); + ptu_int_eq(errcode, 0); + + bcache = pt_section_bcache(sfix->section); + ptu_null(bcache); + + errcode = pt_section_unmap(sfix->section); + ptu_int_eq(errcode, 0); + + return ptu_passed(); +} + +static struct ptunit_result bcache_alloc_free(struct section_fixture *sfix) +{ + uint8_t bytes[] = { 0xcc, 0x2, 0x4, 0x6 }; + struct pt_block_cache *bcache; + int errcode; + + sfix_write(sfix, bytes); + + errcode = pt_mk_section(&sfix->section, sfix->name, 0x1ull, 0x3ull); + ptu_int_eq(errcode, 0); + ptu_ptr(sfix->section); + + errcode = pt_section_map(sfix->section); + ptu_int_eq(errcode, 0); + + errcode = pt_section_alloc_bcache(sfix->section); + ptu_int_eq(errcode, 0); + + bcache = pt_section_bcache(sfix->section); + ptu_ptr(bcache); + ptu_uint_eq(bcache->nentries, sfix->section->size); + + errcode = pt_section_unmap(sfix->section); + ptu_int_eq(errcode, 0); + + bcache = pt_section_bcache(sfix->section); + ptu_null(bcache); + + return ptu_passed(); +} + +static struct ptunit_result bcache_alloc_twice(struct section_fixture *sfix) +{ + uint8_t bytes[] = { 0xcc, 0x2, 0x4, 0x6 }; + int errcode; + + sfix_write(sfix, bytes); + + errcode = pt_mk_section(&sfix->section, sfix->name, 0x1ull, 0x3ull); + ptu_int_eq(errcode, 0); + ptu_ptr(sfix->section); + + errcode = pt_section_map(sfix->section); + ptu_int_eq(errcode, 0); + + errcode = pt_section_alloc_bcache(sfix->section); + ptu_int_eq(errcode, 0); + + errcode = pt_section_alloc_bcache(sfix->section); + ptu_int_eq(errcode, 0); + + errcode = pt_section_unmap(sfix->section); + ptu_int_eq(errcode, 0); + + return ptu_passed(); +} + +static struct ptunit_result bcache_alloc_nomap(struct section_fixture *sfix) +{ + uint8_t bytes[] = { 0xcc, 0x2, 0x4, 0x6 }; + int errcode; + + sfix_write(sfix, bytes); + + errcode = pt_mk_section(&sfix->section, sfix->name, 0x1ull, 0x3ull); + ptu_int_eq(errcode, 0); + ptu_ptr(sfix->section); + + errcode = pt_section_alloc_bcache(sfix->section); + ptu_int_eq(errcode, -pte_internal); + + return ptu_passed(); +} + +static struct ptunit_result memsize_nomap(struct section_fixture *sfix) +{ + uint64_t memsize; + uint8_t bytes[] = { 0xcc, 0x2, 0x4, 0x6 }; + int errcode; + + sfix_write(sfix, bytes); + + errcode = pt_mk_section(&sfix->section, sfix->name, 0x1ull, 0x3ull); + ptu_int_eq(errcode, 0); + ptu_ptr(sfix->section); + + errcode = pt_section_memsize(sfix->section, &memsize); + ptu_int_eq(errcode, 0); + ptu_uint_eq(memsize, 0ull); + + return ptu_passed(); +} + +static struct ptunit_result memsize_unmap(struct section_fixture *sfix) +{ + uint64_t memsize; + uint8_t bytes[] = { 0xcc, 0x2, 0x4, 0x6 }; + int errcode; + + sfix_write(sfix, bytes); + + errcode = pt_mk_section(&sfix->section, sfix->name, 0x1ull, 0x3ull); + ptu_int_eq(errcode, 0); + ptu_ptr(sfix->section); + + errcode = pt_section_map(sfix->section); + ptu_int_eq(errcode, 0); + + errcode = pt_section_unmap(sfix->section); + ptu_int_eq(errcode, 0); + + errcode = pt_section_memsize(sfix->section, &memsize); + ptu_int_eq(errcode, 0); + ptu_uint_eq(memsize, 0ull); + + return ptu_passed(); +} + +static struct ptunit_result memsize_map_nobcache(struct section_fixture *sfix) +{ + uint64_t memsize; + uint8_t bytes[] = { 0xcc, 0x2, 0x4, 0x6 }; + int errcode; + + sfix_write(sfix, bytes); + + errcode = pt_mk_section(&sfix->section, sfix->name, 0x1ull, 0x3ull); + ptu_int_eq(errcode, 0); + ptu_ptr(sfix->section); + + errcode = pt_section_map(sfix->section); + ptu_int_eq(errcode, 0); + + memsize = 0xfefefefefefefefeull; + + errcode = pt_section_memsize(sfix->section, &memsize); + ptu_int_eq(errcode, 0); + ptu_uint_ge(memsize, 0ull); + ptu_uint_le(memsize, 0x2000ull); + + errcode = pt_section_unmap(sfix->section); + ptu_int_eq(errcode, 0); + + return ptu_passed(); +} + +static struct ptunit_result memsize_map_bcache(struct section_fixture *sfix) +{ + uint64_t memsize; + uint8_t bytes[] = { 0xcc, 0x2, 0x4, 0x6 }; + int errcode; + + sfix_write(sfix, bytes); + + errcode = pt_mk_section(&sfix->section, sfix->name, 0x1ull, 0x3ull); + ptu_int_eq(errcode, 0); + ptu_ptr(sfix->section); + + errcode = pt_section_map(sfix->section); + ptu_int_eq(errcode, 0); + + errcode = pt_section_alloc_bcache(sfix->section); + ptu_int_eq(errcode, 0); + + errcode = pt_section_memsize(sfix->section, &memsize); + ptu_int_eq(errcode, 0); + ptu_uint_ge(memsize, + sfix->section->size * sizeof(struct pt_bcache_entry)); + + errcode = pt_section_unmap(sfix->section); + ptu_int_eq(errcode, 0); + + return ptu_passed(); +} + +static struct ptunit_result sfix_init(struct section_fixture *sfix) +{ + int errcode; + + sfix->section = NULL; + sfix->file = NULL; + sfix->name = NULL; + + errcode = ptunit_mkfile(&sfix->file, &sfix->name, "wb"); + ptu_int_eq(errcode, 0); + + ptu_test(ptunit_thrd_init, &sfix->thrd); + + return ptu_passed(); +} + +static struct ptunit_result sfix_fini(struct section_fixture *sfix) +{ + char *filename; + FILE *file; + int thrd, errcode; + + ptu_test(ptunit_thrd_fini, &sfix->thrd); + + if (sfix->section) { + pt_section_put(sfix->section); + sfix->section = NULL; + } + + filename = sfix->name; + file = sfix->file; + sfix->name = NULL; + sfix->file = NULL; + + /* Try removing the file while we still have it open to avoid races + * with others re-using the temporary filename. + * + * On some systems that may not be possible and we can choose between: + * + * - guaranteed leaking files or + * - running the risk of removing someone elses file + * + * We choose the latter. Assuming those systems behave consistently, + * removing someone elses file should only succeed if it isn't open at + * the moment we try removing it. Given that this is a temporary file, + * we should be able to rule out accidental name clashes with + * non-termporary files. + */ + if (filename && file) { + errcode = remove(filename); + if (!errcode) { + free(filename); + filename = NULL; + } + } + + if (file) + fclose(file); + + if (filename) { + (void) remove(filename); + free(filename); + } + + for (thrd = 0; thrd < sfix->thrd.nthreads; ++thrd) + ptu_int_eq(sfix->thrd.result[thrd], 0); + + return ptu_passed(); +} + +int main(int argc, char **argv) +{ + struct section_fixture sfix; + struct ptunit_suite suite; + + sfix.init = sfix_init; + sfix.fini = sfix_fini; + + suite = ptunit_mk_suite(argc, argv); + + ptu_run_f(suite, create, sfix); + ptu_run_f(suite, create_bad_offset, sfix); + ptu_run_f(suite, create_truncated, sfix); + ptu_run_f(suite, create_empty, sfix); + + ptu_run(suite, filename_null); + ptu_run(suite, offset_null); + ptu_run(suite, size_null); + ptu_run(suite, get_null); + ptu_run(suite, put_null); + ptu_run(suite, attach_null); + ptu_run(suite, detach_null); + ptu_run(suite, map_null); + ptu_run(suite, unmap_null); + ptu_run(suite, cache_null); + + ptu_run_f(suite, get_overflow, sfix); + ptu_run_f(suite, attach_overflow, sfix); + ptu_run_f(suite, attach_bad_ucount, sfix); + ptu_run_f(suite, map_change, sfix); + ptu_run_f(suite, map_put, sfix); + ptu_run_f(suite, unmap_nomap, sfix); + ptu_run_f(suite, map_overflow, sfix); + ptu_run_f(suite, get_put, sfix); + ptu_run_f(suite, attach_detach, sfix); + ptu_run_f(suite, attach_bad_iscache, sfix); + ptu_run_f(suite, detach_bad_iscache, sfix); + ptu_run_f(suite, map_unmap, sfix); + ptu_run_f(suite, attach_map, sfix); + ptu_run_f(suite, attach_bad_map, sfix); + ptu_run_f(suite, attach_map_overflow, sfix); + ptu_run_f(suite, read, sfix); + ptu_run_f(suite, read_null, sfix); + ptu_run_f(suite, read_offset, sfix); + ptu_run_f(suite, read_truncated, sfix); + ptu_run_f(suite, read_from_truncated, sfix); + ptu_run_f(suite, read_nomem, sfix); + ptu_run_f(suite, read_overflow, sfix); + ptu_run_f(suite, read_overflow_32bit, sfix); + ptu_run_f(suite, read_nomap, sfix); + ptu_run_f(suite, read_unmap_map, sfix); + + ptu_run_f(suite, init_no_bcache, sfix); + ptu_run_f(suite, bcache_alloc_free, sfix); + ptu_run_f(suite, bcache_alloc_twice, sfix); + ptu_run_f(suite, bcache_alloc_nomap, sfix); + + ptu_run_f(suite, memsize_null, sfix); + ptu_run_f(suite, memsize_nomap, sfix); + ptu_run_f(suite, memsize_unmap, sfix); + ptu_run_f(suite, memsize_map_nobcache, sfix); + ptu_run_f(suite, memsize_map_bcache, sfix); + + ptu_run_fp(suite, stress, sfix, worker_bcache); + ptu_run_fp(suite, stress, sfix, worker_read); + + return ptunit_report(&suite); +} diff --git a/libipt/test/src/ptunit-sync.c b/libipt/test/src/ptunit-sync.c new file mode 100644 index 0000000000000..b42304f5e6631 --- /dev/null +++ b/libipt/test/src/ptunit-sync.c @@ -0,0 +1,306 @@ +/* + * Copyright (c) 2014-2019, Intel Corporation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of Intel Corporation nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "ptunit.h" + +#include "pt_sync.h" +#include "pt_opcodes.h" + +#include "intel-pt.h" + + +/* A test fixture for sync tests. */ +struct sync_fixture { + /* The trace buffer. */ + uint8_t buffer[1024]; + + /* A trace configuration. */ + struct pt_config config; + + /* The test fixture initialization and finalization functions. */ + struct ptunit_result (*init)(struct sync_fixture *); + struct ptunit_result (*fini)(struct sync_fixture *); +}; + +static struct ptunit_result sfix_init(struct sync_fixture *sfix) +{ + memset(sfix->buffer, 0xcd, sizeof(sfix->buffer)); + + memset(&sfix->config, 0, sizeof(sfix->config)); + sfix->config.size = sizeof(sfix->config); + sfix->config.begin = sfix->buffer; + sfix->config.end = sfix->buffer + sizeof(sfix->buffer); + + return ptu_passed(); +} + +static void sfix_encode_psb(uint8_t *pos) +{ + int i; + + *pos++ = pt_opc_psb; + *pos++ = pt_ext_psb; + + for (i = 0; i < pt_psb_repeat_count; ++i) { + *pos++ = pt_psb_hi; + *pos++ = pt_psb_lo; + } +} + + +static struct ptunit_result sync_fwd_null(struct sync_fixture *sfix) +{ + const uint8_t *sync; + int errcode; + + errcode = pt_sync_forward(NULL, sfix->config.begin, &sfix->config); + ptu_int_eq(errcode, -pte_internal); + + errcode = pt_sync_forward(&sync, NULL, &sfix->config); + ptu_int_eq(errcode, -pte_internal); + + errcode = pt_sync_forward(&sync, sfix->config.begin, NULL); + ptu_int_eq(errcode, -pte_internal); + + return ptu_passed(); +} + +static struct ptunit_result sync_bwd_null(struct sync_fixture *sfix) +{ + const uint8_t *sync; + int errcode; + + errcode = pt_sync_backward(NULL, sfix->config.begin, &sfix->config); + ptu_int_eq(errcode, -pte_internal); + + errcode = pt_sync_backward(&sync, NULL, &sfix->config); + ptu_int_eq(errcode, -pte_internal); + + errcode = pt_sync_backward(&sync, sfix->config.begin, NULL); + ptu_int_eq(errcode, -pte_internal); + + return ptu_passed(); +} + +static struct ptunit_result sync_fwd_empty(struct sync_fixture *sfix) +{ + const uint8_t *sync; + int errcode; + + sfix->config.end = sfix->config.begin; + + errcode = pt_sync_forward(&sync, sfix->config.begin, &sfix->config); + ptu_int_eq(errcode, -pte_eos); + + return ptu_passed(); +} + +static struct ptunit_result sync_bwd_empty(struct sync_fixture *sfix) +{ + const uint8_t *sync; + int errcode; + + sfix->config.end = sfix->config.begin; + + errcode = pt_sync_backward(&sync, sfix->config.end, &sfix->config); + ptu_int_eq(errcode, -pte_eos); + + return ptu_passed(); +} + +static struct ptunit_result sync_fwd_none(struct sync_fixture *sfix) +{ + const uint8_t *sync; + int errcode; + + errcode = pt_sync_forward(&sync, sfix->config.begin, &sfix->config); + ptu_int_eq(errcode, -pte_eos); + + return ptu_passed(); +} + +static struct ptunit_result sync_bwd_none(struct sync_fixture *sfix) +{ + const uint8_t *sync; + int errcode; + + errcode = pt_sync_backward(&sync, sfix->config.end, &sfix->config); + ptu_int_eq(errcode, -pte_eos); + + return ptu_passed(); +} + +static struct ptunit_result sync_fwd_here(struct sync_fixture *sfix) +{ + const uint8_t *sync; + int errcode; + + sfix_encode_psb(sfix->config.begin); + + errcode = pt_sync_forward(&sync, sfix->config.begin, &sfix->config); + ptu_int_eq(errcode, 0); + ptu_ptr_eq(sync, sfix->config.begin); + + return ptu_passed(); +} + +static struct ptunit_result sync_bwd_here(struct sync_fixture *sfix) +{ + const uint8_t *sync; + int errcode; + + sfix_encode_psb(sfix->config.end - ptps_psb); + + errcode = pt_sync_backward(&sync, sfix->config.end, &sfix->config); + ptu_int_eq(errcode, 0); + ptu_ptr_eq(sync, sfix->config.end - ptps_psb); + + return ptu_passed(); +} + +static struct ptunit_result sync_fwd(struct sync_fixture *sfix) +{ + const uint8_t *sync; + int errcode; + + sfix_encode_psb(sfix->config.begin + 0x23); + + errcode = pt_sync_forward(&sync, sfix->config.begin, &sfix->config); + ptu_int_eq(errcode, 0); + ptu_ptr_eq(sync, sfix->config.begin + 0x23); + + return ptu_passed(); +} + +static struct ptunit_result sync_bwd(struct sync_fixture *sfix) +{ + const uint8_t *sync; + int errcode; + + sfix_encode_psb(sfix->config.begin + 0x23); + + errcode = pt_sync_backward(&sync, sfix->config.end, &sfix->config); + ptu_int_eq(errcode, 0); + ptu_ptr_eq(sync, sfix->config.begin + 0x23); + + return ptu_passed(); +} + +static struct ptunit_result sync_fwd_past(struct sync_fixture *sfix) +{ + const uint8_t *sync; + int errcode; + + sfix_encode_psb(sfix->config.begin); + + errcode = pt_sync_forward(&sync, sfix->config.begin + ptps_psb, + &sfix->config); + ptu_int_eq(errcode, -pte_eos); + + return ptu_passed(); +} + +static struct ptunit_result sync_bwd_past(struct sync_fixture *sfix) +{ + const uint8_t *sync; + int errcode; + + sfix_encode_psb(sfix->config.end - ptps_psb); + + errcode = pt_sync_backward(&sync, sfix->config.end - ptps_psb, + &sfix->config); + ptu_int_eq(errcode, -pte_eos); + + return ptu_passed(); +} + +static struct ptunit_result sync_fwd_cutoff(struct sync_fixture *sfix) +{ + const uint8_t *sync; + int errcode; + + sfix_encode_psb(sfix->config.begin); + sfix_encode_psb(sfix->config.end - ptps_psb); + sfix->config.begin += 1; + sfix->config.end -= 1; + + errcode = pt_sync_forward(&sync, sfix->config.begin, &sfix->config); + ptu_int_eq(errcode, -pte_eos); + + return ptu_passed(); +} + +static struct ptunit_result sync_bwd_cutoff(struct sync_fixture *sfix) +{ + const uint8_t *sync; + int errcode; + + sfix_encode_psb(sfix->config.begin); + sfix_encode_psb(sfix->config.end - ptps_psb); + sfix->config.begin += 1; + sfix->config.end -= 1; + + errcode = pt_sync_backward(&sync, sfix->config.end, &sfix->config); + ptu_int_eq(errcode, -pte_eos); + + return ptu_passed(); +} + +int main(int argc, char **argv) +{ + struct sync_fixture sfix; + struct ptunit_suite suite; + + sfix.init = sfix_init; + sfix.fini = NULL; + + suite = ptunit_mk_suite(argc, argv); + + ptu_run_f(suite, sync_fwd_null, sfix); + ptu_run_f(suite, sync_bwd_null, sfix); + + ptu_run_f(suite, sync_fwd_empty, sfix); + ptu_run_f(suite, sync_bwd_empty, sfix); + + ptu_run_f(suite, sync_fwd_none, sfix); + ptu_run_f(suite, sync_bwd_none, sfix); + + ptu_run_f(suite, sync_fwd_here, sfix); + ptu_run_f(suite, sync_bwd_here, sfix); + + ptu_run_f(suite, sync_fwd, sfix); + ptu_run_f(suite, sync_bwd, sfix); + + ptu_run_f(suite, sync_fwd_past, sfix); + ptu_run_f(suite, sync_bwd_past, sfix); + + ptu_run_f(suite, sync_fwd_cutoff, sfix); + ptu_run_f(suite, sync_bwd_cutoff, sfix); + + return ptunit_report(&suite); +} diff --git a/libipt/test/src/ptunit-time.c b/libipt/test/src/ptunit-time.c new file mode 100644 index 0000000000000..c6a1c4715221c --- /dev/null +++ b/libipt/test/src/ptunit-time.c @@ -0,0 +1,399 @@ +/* + * Copyright (c) 2014-2019, Intel Corporation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of Intel Corporation nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "pt_time.h" + +#include "intel-pt.h" + +#include "ptunit.h" + + +/* A time unit test fixture. */ + +struct time_fixture { + /* The configuration to use. */ + struct pt_config config; + + /* The calibration to use. */ + struct pt_time_cal tcal; + + /* The time struct to update. */ + struct pt_time time; + + /* The test fixture initialization and finalization functions. */ + struct ptunit_result (*init)(struct time_fixture *); + struct ptunit_result (*fini)(struct time_fixture *); +}; + +static struct ptunit_result tfix_init(struct time_fixture *tfix) +{ + memset(&tfix->config, 0, sizeof(tfix->config)); + tfix->config.size = sizeof(tfix->config); + tfix->config.cpuid_0x15_eax = 2; + tfix->config.cpuid_0x15_ebx = 1; + tfix->config.mtc_freq = 4; + + pt_tcal_init(&tfix->tcal); + pt_tcal_set_fcr(&tfix->tcal, 0x2ull << pt_tcal_fcr_shr); + + pt_time_init(&tfix->time); + + return ptu_passed(); +} + + +static struct ptunit_result tsc_null(struct time_fixture *tfix) +{ + struct pt_packet_tsc packet; + int errcode; + + errcode = pt_time_update_tsc(NULL, &packet, &tfix->config); + ptu_int_eq(errcode, -pte_internal); + + errcode = pt_time_update_tsc(&tfix->time, NULL, &tfix->config); + ptu_int_eq(errcode, -pte_internal); + + return ptu_passed(); +} + +static struct ptunit_result cbr_null(struct time_fixture *tfix) +{ + struct pt_packet_cbr packet; + int errcode; + + errcode = pt_time_update_cbr(NULL, &packet, &tfix->config); + ptu_int_eq(errcode, -pte_internal); + + errcode = pt_time_update_cbr(&tfix->time, NULL, &tfix->config); + ptu_int_eq(errcode, -pte_internal); + + return ptu_passed(); +} + +static struct ptunit_result tma_null(struct time_fixture *tfix) +{ + struct pt_packet_tma packet; + int errcode; + + errcode = pt_time_update_tma(NULL, &packet, &tfix->config); + ptu_int_eq(errcode, -pte_internal); + + errcode = pt_time_update_tma(&tfix->time, NULL, &tfix->config); + ptu_int_eq(errcode, -pte_internal); + + errcode = pt_time_update_tma(&tfix->time, &packet, NULL); + ptu_int_eq(errcode, -pte_internal); + + return ptu_passed(); +} + +static struct ptunit_result mtc_null(struct time_fixture *tfix) +{ + struct pt_packet_mtc packet; + int errcode; + + errcode = pt_time_update_mtc(NULL, &packet, &tfix->config); + ptu_int_eq(errcode, -pte_internal); + + errcode = pt_time_update_mtc(&tfix->time, NULL, &tfix->config); + ptu_int_eq(errcode, -pte_internal); + + errcode = pt_time_update_mtc(&tfix->time, &packet, NULL); + ptu_int_eq(errcode, -pte_internal); + + return ptu_passed(); +} + +static struct ptunit_result cyc_null(struct time_fixture *tfix) +{ + struct pt_packet_cyc packet; + int errcode; + + errcode = pt_time_update_cyc(NULL, &packet, &tfix->config, 0ull); + ptu_int_eq(errcode, -pte_internal); + + errcode = pt_time_update_cyc(&tfix->time, NULL, &tfix->config, 0ull); + ptu_int_eq(errcode, -pte_internal); + + errcode = pt_time_update_cyc(&tfix->time, &packet, NULL, 0ull); + ptu_int_eq(errcode, -pte_internal); + + return ptu_passed(); +} + +static struct ptunit_result query_tsc_null(struct time_fixture *tfix) +{ + uint64_t tsc; + int errcode; + + errcode = pt_time_query_tsc(NULL, NULL, NULL, &tfix->time); + ptu_int_eq(errcode, -pte_internal); + + errcode = pt_time_query_tsc(&tsc, NULL, NULL, NULL); + ptu_int_eq(errcode, -pte_internal); + + return ptu_passed(); +} + +static struct ptunit_result query_tsc_none(struct time_fixture *tfix) +{ + uint64_t tsc; + int errcode; + + errcode = pt_time_query_tsc(&tsc, NULL, NULL, &tfix->time); + ptu_int_eq(errcode, -pte_no_time); + + return ptu_passed(); +} + +static struct ptunit_result query_cbr_null(struct time_fixture *tfix) +{ + uint32_t cbr; + int errcode; + + errcode = pt_time_query_cbr(NULL, &tfix->time); + ptu_int_eq(errcode, -pte_internal); + + errcode = pt_time_query_cbr(&cbr, NULL); + ptu_int_eq(errcode, -pte_internal); + + return ptu_passed(); +} + +static struct ptunit_result query_cbr_none(struct time_fixture *tfix) +{ + uint32_t cbr; + int errcode; + + errcode = pt_time_query_cbr(&cbr, &tfix->time); + ptu_int_eq(errcode, -pte_no_cbr); + + return ptu_passed(); +} + +static struct ptunit_result tcal_cbr_null(struct time_fixture *tfix) +{ + struct pt_packet_cbr packet; + int errcode; + + errcode = pt_tcal_update_cbr(NULL, &packet, &tfix->config); + ptu_int_eq(errcode, -pte_internal); + + return ptu_passed(); +} + +static struct ptunit_result tcal_cbr_zero(struct time_fixture *tfix) +{ + struct pt_packet_cbr packet; + struct pt_config config; + int errcode; + + config = tfix->config; + config.nom_freq = 1; + packet.ratio = 0; + + errcode = pt_tcal_update_cbr(&tfix->tcal, &packet, &config); + ptu_int_eq(errcode, -pte_bad_packet); + + return ptu_passed(); +} + +static struct ptunit_result tcal_mtc_null(struct time_fixture *tfix) +{ + struct pt_packet_mtc packet; + int errcode; + + errcode = pt_tcal_update_mtc(NULL, &packet, &tfix->config); + ptu_int_eq(errcode, -pte_internal); + + errcode = pt_tcal_update_mtc(&tfix->tcal, NULL, &tfix->config); + ptu_int_eq(errcode, -pte_internal); + + errcode = pt_tcal_update_mtc(&tfix->tcal, &packet, NULL); + ptu_int_eq(errcode, -pte_internal); + + return ptu_passed(); +} + +static struct ptunit_result tcal_cyc_null(struct time_fixture *tfix) +{ + struct pt_packet_cyc packet; + int errcode; + + errcode = pt_tcal_update_cyc(NULL, &packet, &tfix->config); + ptu_int_eq(errcode, -pte_internal); + + errcode = pt_tcal_update_cyc(&tfix->tcal, NULL, &tfix->config); + ptu_int_eq(errcode, -pte_internal); + + return ptu_passed(); +} + +static struct ptunit_result tsc(struct time_fixture *tfix) +{ + struct pt_packet_tsc packet; + uint64_t tsc; + uint32_t lost_mtc, lost_cyc; + int errcode; + + packet.tsc = 0xdedededeull; + + errcode = pt_time_update_tsc(&tfix->time, &packet, &tfix->config); + ptu_int_eq(errcode, 0); + + errcode = pt_time_query_tsc(&tsc, &lost_mtc, &lost_cyc, &tfix->time); + ptu_int_eq(errcode, 0); + + ptu_uint_eq(tsc, 0xdedededeull); + ptu_uint_eq(lost_mtc, 0); + ptu_uint_eq(lost_cyc, 0); + + return ptu_passed(); +} + +static struct ptunit_result cbr(struct time_fixture *tfix) +{ + struct pt_packet_cbr packet; + uint32_t cbr; + int errcode; + + packet.ratio = 0x38; + + errcode = pt_time_update_cbr(&tfix->time, &packet, &tfix->config); + ptu_int_eq(errcode, 0); + + errcode = pt_time_query_cbr(&cbr, &tfix->time); + ptu_int_eq(errcode, 0); + + ptu_uint_eq(cbr, 0x38); + + return ptu_passed(); +} + +static struct ptunit_result cbr_zero(struct time_fixture *tfix) +{ + struct pt_packet_cbr packet; + int errcode; + + packet.ratio = 0; + + errcode = pt_time_update_cbr(&tfix->time, &packet, &tfix->config); + ptu_int_eq(errcode, -pte_bad_packet); + + return ptu_passed(); +} + +static struct ptunit_result tma(struct time_fixture *tfix) +{ + struct pt_packet_tma packet; + int errcode; + + packet.ctc = 0xdc; + packet.fc = 0xf; + + errcode = pt_time_update_tma(&tfix->time, &packet, &tfix->config); + ptu_int_eq(errcode, -pte_bad_context); + + return ptu_passed(); +} + +static struct ptunit_result mtc(struct time_fixture *tfix) +{ + struct pt_packet_mtc packet; + uint64_t tsc; + int errcode; + + packet.ctc = 0xdc; + + errcode = pt_time_update_mtc(&tfix->time, &packet, &tfix->config); + ptu_int_eq(errcode, 0); + + errcode = pt_time_query_tsc(&tsc, NULL, NULL, &tfix->time); + ptu_int_eq(errcode, -pte_no_time); + + return ptu_passed(); +} + +static struct ptunit_result cyc(struct time_fixture *tfix) +{ + struct pt_packet_cyc packet; + uint64_t fcr, tsc; + int errcode; + + errcode = pt_tcal_fcr(&fcr, &tfix->tcal); + ptu_int_eq(errcode, 0); + + packet.value = 0xdc; + + errcode = pt_time_update_cyc(&tfix->time, &packet, &tfix->config, fcr); + ptu_int_eq(errcode, 0); + + errcode = pt_time_query_tsc(&tsc, NULL, NULL, &tfix->time); + ptu_int_eq(errcode, -pte_no_time); + + return ptu_passed(); +} + + +int main(int argc, char **argv) +{ + struct ptunit_suite suite; + struct time_fixture tfix; + + suite = ptunit_mk_suite(argc, argv); + + tfix.init = tfix_init; + tfix.fini = NULL; + + ptu_run_f(suite, tsc_null, tfix); + ptu_run_f(suite, cbr_null, tfix); + ptu_run_f(suite, tma_null, tfix); + ptu_run_f(suite, mtc_null, tfix); + ptu_run_f(suite, cyc_null, tfix); + + ptu_run_f(suite, query_tsc_null, tfix); + ptu_run_f(suite, query_tsc_none, tfix); + ptu_run_f(suite, query_cbr_null, tfix); + ptu_run_f(suite, query_cbr_none, tfix); + + ptu_run_f(suite, tcal_cbr_null, tfix); + ptu_run_f(suite, tcal_cbr_zero, tfix); + ptu_run_f(suite, tcal_mtc_null, tfix); + ptu_run_f(suite, tcal_cyc_null, tfix); + + ptu_run_f(suite, tsc, tfix); + ptu_run_f(suite, cbr, tfix); + ptu_run_f(suite, cbr_zero, tfix); + ptu_run_f(suite, tma, tfix); + ptu_run_f(suite, mtc, tfix); + ptu_run_f(suite, cyc, tfix); + + /* The bulk is covered in ptt tests. */ + + return ptunit_report(&suite); +} diff --git a/libipt/test/src/ptunit-tnt_cache.c b/libipt/test/src/ptunit-tnt_cache.c new file mode 100644 index 0000000000000..f207ca02f7554 --- /dev/null +++ b/libipt/test/src/ptunit-tnt_cache.c @@ -0,0 +1,246 @@ +/* + * Copyright (c) 2013-2019, Intel Corporation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of Intel Corporation nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "ptunit.h" + +#include "pt_tnt_cache.h" + +#include "intel-pt.h" + +#include <string.h> + + +static struct ptunit_result init(void) +{ + struct pt_tnt_cache tnt_cache; + + memset(&tnt_cache, 0xcd, sizeof(tnt_cache)); + + pt_tnt_cache_init(&tnt_cache); + + ptu_uint_eq(tnt_cache.tnt, 0ull); + ptu_uint_eq(tnt_cache.index, 0ull); + + return ptu_passed(); +} + +static struct ptunit_result init_null(void) +{ + pt_tnt_cache_init(NULL); + + return ptu_passed(); +} + +static struct ptunit_result is_empty_initial(void) +{ + struct pt_tnt_cache tnt_cache; + int status; + + pt_tnt_cache_init(&tnt_cache); + + status = pt_tnt_cache_is_empty(&tnt_cache); + ptu_int_eq(status, 1); + + return ptu_passed(); +} + +static struct ptunit_result is_empty_no(void) +{ + struct pt_tnt_cache tnt_cache; + int status; + + tnt_cache.index = 1ull; + + status = pt_tnt_cache_is_empty(&tnt_cache); + ptu_int_eq(status, 0); + + return ptu_passed(); +} + +static struct ptunit_result is_empty_yes(void) +{ + struct pt_tnt_cache tnt_cache; + int status; + + tnt_cache.index = 0ull; + + status = pt_tnt_cache_is_empty(&tnt_cache); + ptu_int_eq(status, 1); + + return ptu_passed(); +} + +static struct ptunit_result is_empty_null(void) +{ + int status; + + status = pt_tnt_cache_is_empty(NULL); + ptu_int_eq(status, -pte_invalid); + + return ptu_passed(); +} + +static struct ptunit_result query_taken(void) +{ + struct pt_tnt_cache tnt_cache; + int status; + + tnt_cache.tnt = 1ull; + tnt_cache.index = 1ull; + + status = pt_tnt_cache_query(&tnt_cache); + ptu_int_eq(status, 1); + ptu_uint_eq(tnt_cache.index, 0); + + return ptu_passed(); +} + +static struct ptunit_result query_not_taken(void) +{ + struct pt_tnt_cache tnt_cache; + int status; + + tnt_cache.tnt = 0ull; + tnt_cache.index = 1ull; + + status = pt_tnt_cache_query(&tnt_cache); + ptu_int_eq(status, 0); + ptu_uint_eq(tnt_cache.index, 0); + + return ptu_passed(); +} + +static struct ptunit_result query_empty(void) +{ + struct pt_tnt_cache tnt_cache; + int status; + + tnt_cache.index = 0ull; + + status = pt_tnt_cache_query(&tnt_cache); + ptu_int_eq(status, -pte_bad_query); + + return ptu_passed(); +} + +static struct ptunit_result query_null(void) +{ + int status; + + status = pt_tnt_cache_query(NULL); + ptu_int_eq(status, -pte_invalid); + + return ptu_passed(); +} + +static struct ptunit_result update_tnt(void) +{ + struct pt_tnt_cache tnt_cache; + struct pt_packet_tnt packet; + int errcode; + + pt_tnt_cache_init(&tnt_cache); + + packet.bit_size = 4ull; + packet.payload = 8ull; + + errcode = pt_tnt_cache_update_tnt(&tnt_cache, &packet, NULL); + ptu_int_eq(errcode, 0); + ptu_uint_eq(tnt_cache.tnt, 8ull); + ptu_uint_eq(tnt_cache.index, 1ull << 3); + + return ptu_passed(); +} + +static struct ptunit_result update_tnt_not_empty(void) +{ + struct pt_tnt_cache tnt_cache; + struct pt_packet_tnt packet; + int errcode; + + tnt_cache.tnt = 42ull; + tnt_cache.index = 12ull; + + errcode = pt_tnt_cache_update_tnt(&tnt_cache, &packet, NULL); + ptu_int_eq(errcode, -pte_bad_context); + ptu_uint_eq(tnt_cache.tnt, 42ull); + ptu_uint_eq(tnt_cache.index, 12ull); + + return ptu_passed(); +} + +static struct ptunit_result update_tnt_null_tnt(void) +{ + struct pt_packet_tnt packet; + int errcode; + + errcode = pt_tnt_cache_update_tnt(NULL, &packet, NULL); + ptu_int_eq(errcode, -pte_invalid); + + return ptu_passed(); +} + +static struct ptunit_result update_tnt_null_packet(void) +{ + struct pt_tnt_cache tnt_cache; + int errcode; + + tnt_cache.tnt = 42ull; + tnt_cache.index = 12ull; + + errcode = pt_tnt_cache_update_tnt(&tnt_cache, NULL, NULL); + ptu_int_eq(errcode, -pte_invalid); + ptu_uint_eq(tnt_cache.tnt, 42ull); + ptu_uint_eq(tnt_cache.index, 12ull); + + return ptu_passed(); +} + +int main(int argc, char **argv) +{ + struct ptunit_suite suite; + + suite = ptunit_mk_suite(argc, argv); + + ptu_run(suite, init); + ptu_run(suite, init_null); + ptu_run(suite, is_empty_initial); + ptu_run(suite, is_empty_no); + ptu_run(suite, is_empty_yes); + ptu_run(suite, is_empty_null); + ptu_run(suite, query_taken); + ptu_run(suite, query_not_taken); + ptu_run(suite, query_empty); + ptu_run(suite, query_null); + ptu_run(suite, update_tnt); + ptu_run(suite, update_tnt_not_empty); + ptu_run(suite, update_tnt_null_tnt); + ptu_run(suite, update_tnt_null_packet); + + return ptunit_report(&suite); +} |