1 /*
2 * Check decoding of cachestat syscall.
3 *
4 * Copyright (c) 2023 Dmitry V. Levin <ldv@strace.io>
5 * All rights reserved.
6 *
7 * SPDX-License-Identifier: GPL-2.0-or-later
8 */
9
10 #include "tests.h"
11 #include "scno.h"
12 #include "cachestat.h"
13
14 #include <stdio.h>
15 #include <unistd.h>
16
17 #ifndef SKIP_IF_PROC_IS_UNAVAILABLE
18 # define SKIP_IF_PROC_IS_UNAVAILABLE skip_if_unavailable("/proc/self/fd/")
19 #endif
20
21 #ifndef FD9_PATH
22 # define FD9_PATH "</dev/full>"
23 #endif
24
25 #ifdef RETVAL_INJECTED
26 # define INJ_STR " (INJECTED)\n"
27 #else
28 # define INJ_STR "\n"
29 #endif
30
31 #ifndef TRACE_FDS
32 # define TRACE_FDS 0
33 #endif
34 #ifndef TRACE_PATH
35 # define TRACE_PATH 0
36 #endif
37 #define TRACE_FILTERED (TRACE_FDS || TRACE_PATH)
38
39 static const char *errstr;
40
41 static long
42 k_cachestat(const unsigned int fd, const void *crange,
43 const void *cstat, const unsigned int flags)
44 {
45 const kernel_ulong_t fill = (kernel_ulong_t) 0xbadc0ded00000000ULL;
46 const kernel_ulong_t arg1 = fill | fd;
47 const kernel_ulong_t arg2 = (uintptr_t) crange;
48 const kernel_ulong_t arg3 = (uintptr_t) cstat;
49 const kernel_ulong_t arg4 = fill | flags;
50 const kernel_ulong_t arg5 = fill | 0xdecaffed;
51 const kernel_ulong_t arg6 = fill | 0xdeefaced;
52 const long rc = syscall(__NR_cachestat,
53 arg1, arg2, arg3, arg4, arg5, arg6);
54 errstr = sprintrc(rc);
55 return rc;
56 }
57
58 int
59 main(void)
60 {
61 SKIP_IF_PROC_IS_UNAVAILABLE;
62
63 k_cachestat(-1, 0, 0, 0);
64 #if !TRACE_FILTERED
65 printf("cachestat(-1, NULL, NULL, 0) = %s" INJ_STR, errstr);
66 #endif
67
68 k_cachestat(9, 0, 0, -1U);
69 printf("cachestat(9%s, NULL, NULL, %#x) = %s" INJ_STR,
70 FD9_PATH, -1U, errstr);
71
72 TAIL_ALLOC_OBJECT_CONST_PTR(struct cachestat_range, crange);
73 fill_memory(crange, sizeof(*crange));
74 const void *const bad_crange = (void *) crange + 1;
75
76 k_cachestat(9, bad_crange, 0, 0);
77 printf("cachestat(9%s, %p, NULL, 0) = %s" INJ_STR,
78 FD9_PATH, bad_crange, errstr);
79
80 TAIL_ALLOC_OBJECT_CONST_PTR(struct cachestat, cstat);
81 fill_memory(cstat, sizeof(*cstat));
82 const void *const bad_cstat = (void *) cstat + 1;
83
84 k_cachestat(9, crange, bad_cstat, 0);
85 printf("cachestat(9%s, {off=%#llx, len=%llu}, %p, 0) = %s"
86 INJ_STR, FD9_PATH,
87 (unsigned long long) crange->off,
88 (unsigned long long) crange->len,
89 bad_cstat, errstr);
90
91 if (k_cachestat(9, 0, cstat, 0) < 0) {
92 printf("cachestat(9%s, NULL, %p, 0) = %s" INJ_STR,
93 FD9_PATH, cstat, errstr);
94 } else {
95 printf("cachestat(9%s, NULL, {nr_cache=%llu"
96 ", nr_dirty=%llu, nr_writeback=%llu, nr_evicted=%llu"
97 ", nr_recently_evicted=%llu}, 0) = %s" INJ_STR, FD9_PATH,
98 (unsigned long long) cstat->nr_cache,
99 (unsigned long long) cstat->nr_dirty,
100 (unsigned long long) cstat->nr_writeback,
101 (unsigned long long) cstat->nr_evicted,
102 (unsigned long long) cstat->nr_recently_evicted,
103 errstr);
104 }
105
106 puts("+++ exited with 0 +++");
107 return 0;
108 }