summaryrefslogtreecommitdiff
path: root/libipt/test/src
diff options
context:
space:
mode:
Diffstat (limited to 'libipt/test/src')
-rw-r--r--libipt/test/src/ptunit-asid.c425
-rw-r--r--libipt/test/src/ptunit-block_cache.c370
-rw-r--r--libipt/test/src/ptunit-block_decoder.c351
-rw-r--r--libipt/test/src/ptunit-config.c562
-rw-r--r--libipt/test/src/ptunit-cpp.cpp78
-rw-r--r--libipt/test/src/ptunit-cpu.c173
-rw-r--r--libipt/test/src/ptunit-encoder.c237
-rw-r--r--libipt/test/src/ptunit-event_queue.c470
-rw-r--r--libipt/test/src/ptunit-fetch.c693
-rw-r--r--libipt/test/src/ptunit-ild.c757
-rw-r--r--libipt/test/src/ptunit-image.c2287
-rw-r--r--libipt/test/src/ptunit-image_section_cache.c2031
-rw-r--r--libipt/test/src/ptunit-insn_decoder.c351
-rw-r--r--libipt/test/src/ptunit-last_ip.c374
-rw-r--r--libipt/test/src/ptunit-mapped_section.c198
-rw-r--r--libipt/test/src/ptunit-msec_cache.c419
-rw-r--r--libipt/test/src/ptunit-packet.c859
-rw-r--r--libipt/test/src/ptunit-packet_decoder.c274
-rw-r--r--libipt/test/src/ptunit-query.c2873
-rw-r--r--libipt/test/src/ptunit-retstack.c232
-rw-r--r--libipt/test/src/ptunit-section-file.c192
-rw-r--r--libipt/test/src/ptunit-section.c1463
-rw-r--r--libipt/test/src/ptunit-sync.c306
-rw-r--r--libipt/test/src/ptunit-time.c399
-rw-r--r--libipt/test/src/ptunit-tnt_cache.c246
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(&section, NULL, &status, &mapping, NULL);
+
+ pt_image_init(&image, NULL);
+ errcode = pt_image_add(&image, &section, &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(&section->lock, mtx_plain);
+ if (errcode != thrd_success) {
+ free(section);
+ return -pte_bad_lock;
+ }
+
+ errcode = mtx_init(&section->alock, mtx_plain);
+ if (errcode != thrd_success) {
+ mtx_destroy(&section->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(&section->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(&section->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(&section->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(&section->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(&section->alock);
+ mtx_destroy(&section->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, &section->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(&section, "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, &section, 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, &section, &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, &section, 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(&section, 0, sizeof(section));
+
+ errcode = pt_iscache_add(&cfix->iscache, &section, 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, &section, &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, &section, &laddr, 0);
+ ptu_int_eq(errcode, -pte_bad_image);
+
+ errcode = pt_iscache_lookup(&cfix->iscache, &section, &laddr, -isid);
+ ptu_int_eq(errcode, -pte_bad_image);
+
+ errcode = pt_iscache_lookup(&cfix->iscache, &section, &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, &section, &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, &section,
+ &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, &section,
+ &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, &section,
+ &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, &section, NULL, 0x2000ull, 0x100ull, 0x1000ull);
+
+ psection = pt_msec_section(&msec);
+ ptu_ptr_eq(psection, &section);
+
+ 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(&section, 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(&section, 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);
+}