]> granicus.if.org Git - strace/blob - tests/read-write.c
strace: terminate itself if interrupted by a signal
[strace] / tests / read-write.c
1 /*
2  * Check decoding and dumping of read and write syscalls.
3  *
4  * Copyright (c) 2016 Dmitry V. Levin <ldv@altlinux.org>
5  * Copyright (c) 2016-2018 The strace developers.
6  * All rights reserved.
7  *
8  * SPDX-License-Identifier: GPL-2.0-or-later
9  */
10
11 #include "tests.h"
12
13 #include <fcntl.h>
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <unistd.h>
17 #include <asm/unistd.h>
18
19 static void
20 dump_str(const char *str, const unsigned int len)
21 {
22         static const char chars[256] =
23                 "................................"
24                 " !\"#$%&'()*+,-./0123456789:;<=>?"
25                 "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_"
26                 "`abcdefghijklmnopqrstuvwxyz{|}~."
27                 "................................"
28                 "................................"
29                 "................................"
30                 "................................";
31         unsigned int i;
32
33         for (i = 0; i < len; i += 16) {
34                 unsigned int n = len - i > 16 ? 16 : len - i;
35                 const char *dump = hexdump_memdup(str + i, n);
36
37                 tprintf(" | %05x %-49s  %-16.*s |\n",
38                         i, dump, n, chars + i);
39
40                 free((void *) dump);
41         }
42 }
43
44 static void
45 print_hex(const char *str, const unsigned int len)
46 {
47         const unsigned char *ustr = (const unsigned char *) str;
48         unsigned int i;
49
50         tprintf("\"");
51
52         for (i = 0; i < len; ++i) {
53                 unsigned int c = ustr[i];
54
55                 if (i >= DEFAULT_STRLEN) {
56                         tprintf("\"...");
57                         return;
58                 }
59
60                 switch (c) {
61                 case '\t':
62                         tprintf("\\t"); break;
63                 case '\n':
64                         tprintf("\\n"); break;
65                 case '\v':
66                         tprintf("\\v"); break;
67                 case '\f':
68                         tprintf("\\f"); break;
69                 case '\r':
70                         tprintf("\\r"); break;
71                 default:
72                         tprintf("\\%o", ustr[i]);
73                 }
74         }
75
76         tprintf("\"");
77 }
78
79 static long
80 k_read(unsigned int fd, void *buf, size_t count)
81 {
82         kernel_ulong_t kfd = (kernel_ulong_t) 0xfacefeed00000000ULL | fd;
83         return syscall(__NR_read, kfd, buf, count);
84 }
85
86 static long
87 k_write(unsigned int fd, const void *buf, size_t count)
88 {
89         kernel_ulong_t kfd = (kernel_ulong_t) 0xfacefeed00000000ULL | fd;
90         return syscall(__NR_write, kfd, buf, count);
91 }
92
93 static void
94 test_dump(const unsigned int len, bool err_desc)
95 {
96         static char *buf;
97         const char *rc_str;
98         int in_fd = err_desc ? 5 : 0;
99         int out_fd = err_desc ? 4 : 1;
100
101         if (buf) {
102                 size_t ps1 = get_page_size() - 1;
103                 buf = (void *) (((size_t) buf + ps1) & ~ps1) - len;
104         } else {
105                 buf = tail_alloc(len);
106         }
107
108         long rc = k_read(in_fd, buf, len);
109         rc_str = sprintrc(rc);
110         if (err_desc ^ (rc != (int) len))
111                 perror_msg_and_fail("read: expected %d, returned %ld",
112                                     err_desc ? -1 : (int) len, rc);
113
114         tprintf("%s(%d, ", "read", in_fd);
115         if (!err_desc)
116                 print_hex(buf, len);
117         else
118                 tprintf("%p", buf);
119         tprintf(", %d) = %s\n", len, rc_str);
120         if (!err_desc)
121                 dump_str(buf, len);
122
123         unsigned int i;
124         for (i = 0; i < len; ++i)
125                 buf[i] = i;
126
127         rc = k_write(out_fd, buf, len);
128         rc_str = sprintrc(rc);
129         if (err_desc ^ (rc != (int) len))
130                 perror_msg_and_fail("write: expected %d, returned %ld",
131                                     err_desc ? -1 : (int) len, rc);
132
133         tprintf("%s(%d, ", "write", out_fd);
134         print_hex(buf, len);
135         tprintf(", %d) = %s\n", len, rc_str);
136         dump_str(buf, len);
137
138         if (!len)
139                 buf = 0;
140 }
141
142 int
143 main(void)
144 {
145         tprintf("%s", "");
146
147         skip_if_unavailable("/proc/self/fd/");
148
149         static const char tmp[] = "read-write-tmpfile";
150         if (open(tmp, O_CREAT|O_RDONLY|O_TRUNC, 0600) != 0)
151                 perror_msg_and_fail("creat: %s", tmp);
152         if (open(tmp, O_WRONLY) != 1)
153                 perror_msg_and_fail("open: %s", tmp);
154
155         static const char w_c[] = "0123456789abcde";
156         const unsigned int w_len = LENGTH_OF(w_c);
157         const char *w_d = hexdump_strdup(w_c);
158         const void *w = tail_memdup(w_c, w_len);
159
160         static const char r0_c[] = "01234567";
161         const char *r0_d = hexdump_strdup(r0_c);
162         const unsigned int r0_len = (w_len + 1) / 2;
163         void *r0 = tail_alloc(r0_len);
164
165         static const char r1_c[] = "89abcde";
166         const char *r1_d = hexdump_strdup(r1_c);
167         const unsigned int r1_len = w_len - r0_len;
168         void *r1 = tail_alloc(w_len);
169
170         void *efault = r1 - get_page_size();
171
172         long rc;
173
174         rc = k_write(1, w, 0);
175         if (rc)
176                 perror_msg_and_fail("write: expected 0, returned %ld", rc);
177         tprintf("write(1, \"\", 0) = 0\n");
178
179         rc = k_write(1, efault, 1);
180         if (rc != -1)
181                 perror_msg_and_fail("write: expected -1 EFAULT"
182                                     ", returned %ld", rc);
183         tprintf("write(1, %p, 1) = -1 EFAULT (%m)\n", efault);
184
185         rc = k_write(1, w, w_len);
186         if (rc != (int) w_len)
187                 perror_msg_and_fail("write: expected %u, returned %ld",
188                                     w_len, rc);
189         tprintf("write(1, \"%s\", %u) = %ld\n"
190                 " | 00000 %-49s  %-16s |\n",
191                 w_c, w_len, rc, w_d, w_c);
192         close(1);
193
194         rc = k_read(0, r0, 0);
195         if (rc)
196                 perror_msg_and_fail("read: expected 0, returned %ld", rc);
197         tprintf("read(0, \"\", 0) = 0\n");
198
199         rc = k_read(0, efault, 1);
200         if (rc != -1)
201                 perror_msg_and_fail("read: expected -1, returned %ld", rc);
202         tprintf("read(0, %p, 1) = -1 EFAULT (%m)\n", efault);
203
204         rc = k_read(0, r0, r0_len);
205         if (rc != (int) r0_len)
206                 perror_msg_and_fail("read: expected %u, returned %ld",
207                                     r0_len, rc);
208         tprintf("read(0, \"%s\", %u) = %ld\n"
209                 " | 00000 %-49s  %-16s |\n",
210                 r0_c, r0_len, rc, r0_d, r0_c);
211
212         rc = k_read(0, r1, w_len);
213         if (rc != (int) r1_len)
214                 perror_msg_and_fail("read: expected %u, returned %ld",
215                                     r1_len, rc);
216         tprintf("read(0, \"%s\", %u) = %ld\n"
217                 " | 00000 %-49s  %-16s |\n",
218                 r1_c, w_len, rc, r1_d, r1_c);
219         close(0);
220
221         if (open("/dev/zero", O_RDONLY))
222                 perror_msg_and_fail("open");
223
224         if (open("/dev/null", O_WRONLY) != 1)
225                 perror_msg_and_fail("open");
226
227         if (open("/dev/zero", O_RDONLY) != 4)
228                 perror_msg_and_fail("open");
229
230         if (open("/dev/null", O_WRONLY) != 5)
231                 perror_msg_and_fail("open");
232
233         unsigned int i;
234         for (i = 0; i <= DEFAULT_STRLEN; ++i)
235                 test_dump(i, false);
236
237         test_dump(256, true);
238
239         tprintf("+++ exited with 0 +++\n");
240         return 0;
241 }