]> granicus.if.org Git - strace/blob - tests/process_vm_readv_writev.c
tests: use fixed timestamps in utime related tests
[strace] / tests / process_vm_readv_writev.c
1 /*
2  * Check decoding of process_vm_readv/process_vm_writev syscall.
3  *
4  * Copyright (c) 2016 Eugene Syromyatnikov <evgsyr@gmail.com>
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. The name of the author may not be used to endorse or promote products
16  *    derived from this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29
30 #include <inttypes.h>
31 #include <stdio.h>
32 #include <unistd.h>
33 #include <sys/uio.h>
34
35 #if OP_WR
36 # define in_iovec  rmt_iovec
37 # define out_iovec lcl_iovec
38 # define in_iov    rmt_iov
39 # define out_iov   lcl_iov
40 #else
41 # define in_iovec  lcl_iovec
42 # define out_iovec rmt_iovec
43 # define in_iov    lcl_iov
44 # define out_iov   rmt_iov
45 #endif
46
47 typedef void (*iov_print_fn)(const struct iovec *, const void *, long);
48
49 enum { MAX_SEGM_COUNT = 2, MAX_STR_LEN = 5 };
50
51 struct print_iov_arg {
52         uint32_t count;
53         uint32_t valid    :1,
54                  string   :1,
55                  addr_term:1,
56                  check_rc :1;
57         uint32_t str_segms;
58         uint8_t  str_base[MAX_SEGM_COUNT];
59         uint8_t  str_size[MAX_SEGM_COUNT];
60 };
61
62 static void
63 print_iov(const struct iovec *iov, const void *arg_ptr, long rc)
64 {
65         const struct print_iov_arg *arg = arg_ptr;
66         uint32_t i;
67         uint32_t num_segm = 0;
68         uint64_t segm_offs = 0;
69
70         if (!arg || !arg->valid) {
71                 if (iov)
72                         printf("%p", iov);
73                 else
74                         printf("NULL");
75
76                 return;
77         }
78
79         printf("[");
80
81         for (i = 0; i < arg->count; i++) {
82                 if (i)
83                         printf(", ");
84
85                 if (i >= MAX_STR_LEN) {
86                         printf("...");
87                         break;
88                 }
89
90                 printf("{iov_base=");
91                 if (arg->string && (!arg->check_rc || (rc != -1))) {
92                         uint64_t str_left = iov[i].iov_len;
93                         uint64_t pr_count = 0;
94
95                         printf("\"");
96
97                         while (str_left--) {
98                                 static const char oct_str[] = "01234567";
99                                 uint8_t c = arg->str_base[num_segm] + segm_offs;
100
101                                 if ((num_segm >= arg->str_segms) ||
102                                     (num_segm >= MAX_SEGM_COUNT))
103                                         error_msg_and_fail("print_iov: segment "
104                                                            "count overrun");
105
106                                 if (pr_count++ < MAX_STR_LEN)
107                                         printf("\\%.1s%.1s%d",
108                                                (c >> 6) ?
109                                                oct_str + (c >> 6) : "",
110                                                (c >> 3) ?
111                                                oct_str + ((c >> 3) & 7) : "",
112                                                c & 7);
113
114                                 segm_offs++;
115
116                                 if (segm_offs >= arg->str_size[num_segm]) {
117                                         num_segm++;
118                                         segm_offs = 0;
119                                 }
120                         }
121
122                         printf("\"");
123
124                         if (pr_count > MAX_STR_LEN)
125                                 printf("...");
126                 } else {
127                         if (iov[i].iov_base)
128                                 printf("%p", iov[i].iov_base);
129                         else
130                                 printf("NULL");
131                 }
132
133                 printf(", iov_len=%zu}", iov[i].iov_len);
134         }
135
136         if (arg->addr_term)
137                 printf(", %p", iov + arg->count);
138
139         printf("]");
140 }
141
142 static void
143 do_call(kernel_ulong_t pid,
144         kernel_ulong_t local_iov, const char *local_arg,
145         kernel_ulong_t liovcnt,
146         kernel_ulong_t remote_iov, const char *remote_arg,
147         kernel_ulong_t riovcnt,
148         kernel_ulong_t flags, iov_print_fn pr_iov)
149 {
150         long rc;
151         const char *errstr;
152
153         rc = syscall(OP_NR, pid, local_iov, liovcnt, remote_iov, riovcnt,
154                 flags);
155         errstr = sprintrc(rc);
156
157         printf("%s(%d, ", OP_STR, (int) pid);
158
159         if (pr_iov)
160                 pr_iov((const struct iovec *) (uintptr_t) local_iov, local_arg,
161                         rc);
162         else
163                 printf("%s", local_arg);
164
165         printf(", %lu, ", (unsigned long) liovcnt);
166
167         if (pr_iov)
168                 pr_iov((const struct iovec *) (uintptr_t) remote_iov,
169                        remote_arg, rc);
170         else
171                 printf("%s", remote_arg);
172
173         printf(", %lu, %lu) = %s\n", (unsigned long) riovcnt,
174                 (unsigned long) flags, errstr);
175 }
176
177 kernel_ulong_t
178 ptr_cast(void *ptr)
179 {
180         return (kernel_ulong_t) (uintptr_t) ptr;
181 }
182
183 int
184 main(void)
185 {
186         enum {
187                 SIZE_11 = 2,
188                 SIZE_12 = 3,
189                 SIZE_13 = 4,
190                 SIZE_1 = SIZE_11 + SIZE_12 + SIZE_13,
191                 SIZE_21 = 5,
192                 SIZE_22 = 6,
193                 SIZE_23 = 7,
194                 SIZE_2 = SIZE_21 + SIZE_22 + SIZE_23,
195         };
196
197         enum {
198                 SEGM1_BASE = 0x80,
199                 SEGM2_BASE = 0xA0,
200         };
201
202         static const kernel_ulong_t bogus_pid =
203                 (kernel_ulong_t) 0xbadfaceddeadca57ULL;
204         static const kernel_ulong_t bogus_iovcnt1 =
205                 (kernel_ulong_t) 0xdec0ded1defaced2ULL;
206         static const kernel_ulong_t bogus_iovcnt2 =
207                 (kernel_ulong_t) 0xdec0ded3defaced4ULL;
208         static const kernel_ulong_t bogus_flags =
209                 (kernel_ulong_t) 0xdeadc0deda7adeadULL;
210
211         pid_t my_pid = getpid();
212         char *data1_out = tail_alloc(SIZE_1);
213         char *data2_out = tail_alloc(SIZE_2);
214         char *data1_in  = tail_alloc(SIZE_2);
215         char *data2_in  = tail_alloc(SIZE_1);
216
217         struct iovec bogus_iovec[] = {
218                 { data1_out + SIZE_1, (size_t) 0xdeadfaceca57beefULL },
219                 { data1_in  + SIZE_2, (size_t) 0xbadc0dedda7adeadULL },
220                 { data2_out + SIZE_2, (size_t) 0xf157facedec0ded1ULL },
221                 { data2_in  + SIZE_1, (size_t) 0xdefaced2bea7be57ULL },
222         };
223
224         struct iovec out_iovec[] = {
225                 { data1_out,  SIZE_11 },
226                 { data1_out + SIZE_11,  SIZE_12 },
227                 { data1_out + SIZE_11 + SIZE_12,  SIZE_13 },
228                 { data2_out,  SIZE_21 },
229                 { data2_out + SIZE_21,  SIZE_22 },
230                 { data2_out + SIZE_21 + SIZE_22,  SIZE_23 },
231         };
232         struct iovec in_iovec[] = {
233                 { data1_in,  SIZE_23 },
234                 { data1_in + SIZE_23,  SIZE_22 },
235                 { data1_in + SIZE_23 + SIZE_22,  SIZE_21 },
236                 { data2_in,  SIZE_13 },
237                 { data2_in + SIZE_13,  SIZE_12 },
238                 { data2_in + SIZE_13 + SIZE_12,  SIZE_11 },
239         };
240
241         struct iovec *bogus_iov = tail_memdup(bogus_iovec, sizeof(bogus_iovec));
242         struct iovec *lcl_iov   = tail_memdup(lcl_iovec,   sizeof(lcl_iovec));
243         struct iovec *rmt_iov   = tail_memdup(rmt_iovec,   sizeof(rmt_iovec));
244
245         struct print_iov_arg bogus_arg   = { ARRAY_SIZE(bogus_iovec), 1 };
246         struct print_iov_arg lcl_arg     = { ARRAY_SIZE(lcl_iovec), 1, 1, 0, 0,
247                 2, {SEGM1_BASE, SEGM2_BASE}, {SIZE_1, SIZE_2} };
248         struct print_iov_arg rmt_arg     = { ARRAY_SIZE(rmt_iovec), 1 };
249
250         struct print_iov_arg bogus_arg_cut =
251                 { ARRAY_SIZE(bogus_iovec) - 2, 1, 0, 1 };
252         struct print_iov_arg lcl_arg_cut =
253                 { ARRAY_SIZE(lcl_iovec) - 2, 1, 1, 1, 0, 2,
254                         {SEGM1_BASE + SIZE_11 + SIZE_12, SEGM2_BASE},
255                         {SIZE_13, SIZE_2} };
256         struct print_iov_arg rmt_arg_cut =
257                 { ARRAY_SIZE(rmt_iovec) - 2, 1 };
258
259
260         fill_memory_ex(data1_out, SIZE_1, SEGM1_BASE, SIZE_1);
261         fill_memory_ex(data2_out, SIZE_2, SEGM2_BASE, SIZE_2);
262
263
264         do_call(bogus_pid, (kernel_ulong_t) (uintptr_t) ARG_STR(NULL),
265                 bogus_iovcnt1, (kernel_ulong_t) (uintptr_t) ARG_STR(NULL),
266                 bogus_iovcnt2, bogus_flags, NULL);
267
268         do_call(my_pid, ptr_cast(bogus_iov + ARRAY_SIZE(bogus_iovec)),
269                 "[]", 0, ptr_cast(in_iov + ARRAY_SIZE(in_iovec)), "[]",
270                 0, 0, NULL);
271         do_call(my_pid, ptr_cast(bogus_iov + ARRAY_SIZE(bogus_iovec)), NULL,
272                 bogus_iovcnt1, ptr_cast(in_iov + ARRAY_SIZE(in_iovec)), NULL,
273                 bogus_iovcnt2, 0, print_iov);
274
275         do_call(my_pid, ptr_cast(bogus_iov), (char *) &bogus_arg,
276                 ARRAY_SIZE(bogus_iovec), ptr_cast(rmt_iov + 2),
277                 (char *) &rmt_arg_cut, ARRAY_SIZE(rmt_iovec) - 2, 0, print_iov);
278
279 #if !OP_WR
280         lcl_arg.check_rc = 1;
281         lcl_arg_cut.check_rc = 1;
282 #endif
283
284         do_call(my_pid, ptr_cast(lcl_iov + 2), (char *) &lcl_arg_cut,
285                 ARRAY_SIZE(lcl_iovec) - 1, ptr_cast(bogus_iov + 2),
286                 (char *) &bogus_arg_cut, ARRAY_SIZE(bogus_iovec) - 1, 0,
287                 print_iov);
288
289         lcl_arg_cut.addr_term = 0;
290
291         rmt_arg_cut.addr_term = 1;
292         rmt_arg_cut.count = 5;
293
294         do_call(my_pid, ptr_cast(lcl_iov + 2), (char *) &lcl_arg_cut,
295                 ARRAY_SIZE(lcl_iovec) - 2, ptr_cast(rmt_iov + 1),
296                 (char *) &rmt_arg_cut, ARRAY_SIZE(rmt_iovec), 0, print_iov);
297
298         /* Correct call */
299         do_call(my_pid, ptr_cast(lcl_iov), (char *) &lcl_arg,
300                 ARRAY_SIZE(lcl_iovec), ptr_cast(rmt_iov), (char *) &rmt_arg,
301                 ARRAY_SIZE(rmt_iovec), 0, print_iov);
302
303         puts("+++ exited with 0 +++");
304
305         return 0;
306 }