/* * SPDX-License-Identifier: GPL-2.0-or-later * * Check if we detect all memory accesses expected using plugin API. * Used in conjunction with ./check-plugin-mem-access.sh check script. * Output of this program is the list of patterns expected in plugin output. * * 8,16,32 load/store are tested for all arch. * 64,128 load/store are tested for aarch64/x64. * atomic operations (8,16,32,64) are tested for x64 only. */ #include #include #include #include #if defined(__x86_64__) #include #elif defined(__aarch64__) #include #endif /* __x86_64__ */ static void *data; /* ,store_u8,.*,8,store,0xf1 */ #define PRINT_EXPECTED(function, type, value, action) \ do { \ printf(",%s,.*,%d,%s,%s\n", \ #function, (int) sizeof(type) * 8, action, value); \ } \ while (0) #define DEFINE_STORE(name, type, value) \ \ static void print_expected_store_##name(void) \ { \ PRINT_EXPECTED(store_##name, type, #value, "store"); \ } \ \ static void store_##name(void) \ { \ *((type *)data) = value; \ print_expected_store_##name(); \ } #define DEFINE_ATOMIC_OP(name, type, value) \ \ static void print_expected_atomic_op_##name(void) \ { \ PRINT_EXPECTED(atomic_op_##name, type, "0x0*42", "load"); \ PRINT_EXPECTED(atomic_op_##name, type, #value, "store"); \ } \ \ static void atomic_op_##name(void) \ { \ *((type *)data) = 0x42; \ __sync_val_compare_and_swap((type *)data, 0x42, value); \ print_expected_atomic_op_##name(); \ } #define DEFINE_LOAD(name, type, value) \ \ static void print_expected_load_##name(void) \ { \ PRINT_EXPECTED(load_##name, type, #value, "load"); \ } \ \ static void load_##name(void) \ { \ \ /* volatile forces load to be generated. */ \ volatile type src = *((type *) data); \ volatile type dest = src; \ (void)src, (void)dest; \ print_expected_load_##name(); \ } DEFINE_STORE(u8, uint8_t, 0xf1) DEFINE_LOAD(u8, uint8_t, 0xf1) DEFINE_STORE(u16, uint16_t, 0xf123) DEFINE_LOAD(u16, uint16_t, 0xf123) DEFINE_STORE(u32, uint32_t, 0xff112233) DEFINE_LOAD(u32, uint32_t, 0xff112233) #if defined(__x86_64__) || defined(__aarch64__) DEFINE_STORE(u64, uint64_t, 0xf123456789abcdef) DEFINE_LOAD(u64, uint64_t, 0xf123456789abcdef) static void print_expected_store_u128(void) { PRINT_EXPECTED(store_u128, __int128, "0xf122334455667788f123456789abcdef", "store"); } static void store_u128(void) { #ifdef __x86_64__ _mm_store_si128(data, _mm_set_epi32(0xf1223344, 0x55667788, 0xf1234567, 0x89abcdef)); #else const uint32_t init[4] = {0x89abcdef, 0xf1234567, 0x55667788, 0xf1223344}; uint32x4_t vec = vld1q_u32(init); vst1q_u32(data, vec); #endif /* __x86_64__ */ print_expected_store_u128(); } static void print_expected_load_u128(void) { PRINT_EXPECTED(load_u128, __int128, "0xf122334455667788f123456789abcdef", "load"); } static void load_u128(void) { #ifdef __x86_64__ __m128i var = _mm_load_si128(data); #else uint32x4_t var = vld1q_u32(data); #endif (void) var; print_expected_load_u128(); } #endif /* __x86_64__ || __aarch64__ */ #if defined(__x86_64__) DEFINE_ATOMIC_OP(u8, uint8_t, 0xf1) DEFINE_ATOMIC_OP(u16, uint16_t, 0xf123) DEFINE_ATOMIC_OP(u32, uint32_t, 0xff112233) DEFINE_ATOMIC_OP(u64, uint64_t, 0xf123456789abcdef) #endif /* __x86_64__ */ static void *f(void *p) { return NULL; } int main(void) { /* * We force creation of a second thread to enable cpu flag CF_PARALLEL. * This will generate atomic operations when needed. */ pthread_t thread; pthread_create(&thread, NULL, &f, NULL); pthread_join(thread, NULL); /* allocate storage up to 128 bits */ data = malloc(16); store_u8(); load_u8(); store_u16(); load_u16(); store_u32(); load_u32(); #if defined(__x86_64__) || defined(__aarch64__) store_u64(); load_u64(); store_u128(); load_u128(); #endif /* __x86_64__ || __aarch64__ */ #if defined(__x86_64__) atomic_op_u8(); atomic_op_u16(); atomic_op_u32(); atomic_op_u64(); #endif /* __x86_64__ */ free(data); }