(root)/
strace-6.5/
tests/
read-write.c
       1  /*
       2   * Check decoding and dumping of read and write syscalls.
       3   *
       4   * Copyright (c) 2016 Dmitry V. Levin <ldv@strace.io>
       5   * Copyright (c) 2016-2021 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 "scno.h"
      18  
      19  static void
      20  dump_str_ex(const char *str, const unsigned int len, const int idx_w)
      21  {
      22  	static const char chars[256] =
      23  		"................................"
      24  		" !\"#$%&'()*+,-./0123456789:;<=>?"
      25  		"@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_"
      26  		"`abcdefghijklmnopqrstuvwxyz{|}~."
      27  		"................................"
      28  		"................................"
      29  		"................................"
      30  		"................................";
      31  
      32  	for (unsigned int i = 0; i < len; i += 16) {
      33  		unsigned int n = len - i > 16 ? 16 : len - i;
      34  		const char *dump = hexdump_memdup(str + i, n);
      35  
      36  		tprintf(" | %0*x %-49s  %-16.*s |\n",
      37  			idx_w, i, dump, n, chars + i % 0x100);
      38  
      39  		free((void *) dump);
      40  	}
      41  }
      42  
      43  static void
      44  dump_str(const char *str, const unsigned int len)
      45  {
      46  	dump_str_ex(str, len, 5);
      47  }
      48  
      49  static void
      50  print_hex(const char *str, const unsigned int len)
      51  {
      52  	const unsigned char *ustr = (const unsigned char *) str;
      53  
      54  	tprintf("\"");
      55  
      56  	for (unsigned int i = 0; i < len; ++i) {
      57  		unsigned int c = ustr[i];
      58  
      59  		if (i >= DEFAULT_STRLEN) {
      60  			tprintf("\"...");
      61  			return;
      62  		}
      63  
      64  		switch (c) {
      65  		case '\t':
      66  			tprintf("\\t"); break;
      67  		case '\n':
      68  			tprintf("\\n"); break;
      69  		case '\v':
      70  			tprintf("\\v"); break;
      71  		case '\f':
      72  			tprintf("\\f"); break;
      73  		case '\r':
      74  			tprintf("\\r"); break;
      75  		default:
      76  			tprintf("\\%o", ustr[i]);
      77  		}
      78  	}
      79  
      80  	tprintf("\"");
      81  }
      82  
      83  static long
      84  k_read(unsigned int fd, void *buf, size_t count)
      85  {
      86  	kernel_ulong_t kfd = (kernel_ulong_t) 0xfacefeed00000000ULL | fd;
      87  	return syscall(__NR_read, kfd, buf, count);
      88  }
      89  
      90  static long
      91  k_write(unsigned int fd, const void *buf, size_t count)
      92  {
      93  	kernel_ulong_t kfd = (kernel_ulong_t) 0xfacefeed00000000ULL | fd;
      94  	return syscall(__NR_write, kfd, buf, count);
      95  }
      96  
      97  static void
      98  test_dump(const unsigned int len, bool err_desc)
      99  {
     100  	static char *buf;
     101  	const char *rc_str;
     102  	int in_fd = err_desc ? 5 : 0;
     103  	int out_fd = err_desc ? 4 : 1;
     104  
     105  	if (buf) {
     106  		size_t ps1 = get_page_size() - 1;
     107  		buf = (void *) (((size_t) buf + ps1) & ~ps1) - len;
     108  	} else {
     109  		buf = tail_alloc(len);
     110  	}
     111  
     112  	long rc = k_read(in_fd, buf, len);
     113  	rc_str = sprintrc(rc);
     114  	if (err_desc ^ (rc != (int) len))
     115  		perror_msg_and_fail("read: expected %d, returned %ld",
     116  				    err_desc ? -1 : (int) len, rc);
     117  
     118  	tprintf("%s(%d, ", "read", in_fd);
     119  	if (!err_desc)
     120  		print_hex(buf, len);
     121  	else
     122  		tprintf("%p", buf);
     123  	tprintf(", %d) = %s\n", len, rc_str);
     124  	if (!err_desc)
     125  		dump_str(buf, len);
     126  
     127  	for (unsigned int i = 0; i < len; ++i)
     128  		buf[i] = i;
     129  
     130  	rc = k_write(out_fd, buf, len);
     131  	rc_str = sprintrc(rc);
     132  	if (err_desc ^ (rc != (int) len))
     133  		perror_msg_and_fail("write: expected %d, returned %ld",
     134  				    err_desc ? -1 : (int) len, rc);
     135  
     136  	tprintf("%s(%d, ", "write", out_fd);
     137  	print_hex(buf, len);
     138  	tprintf(", %d) = %s\n", len, rc_str);
     139  	dump_str(buf, len);
     140  
     141  	if (!len)
     142  		buf = 0;
     143  }
     144  
     145  int
     146  main(void)
     147  {
     148  	tprintf("%s", "");
     149  
     150  	skip_if_unavailable("/proc/self/fd/");
     151  
     152  	static const char tmp[] = "read-write-tmpfile";
     153  	bool need_cleanup = true;
     154  	long rc;
     155  
     156  	rc = open(tmp, O_RDONLY, 0600);
     157  	if (rc < 0) {
     158  		rc = open(tmp, O_CREAT|O_EXCL|O_RDONLY, 0600);
     159  		need_cleanup = false;
     160  	}
     161  	if (rc != 0)
     162  		perror_msg_and_fail("creat: %s", tmp);
     163  	if (open(tmp, O_TRUNC|O_WRONLY) != 1)
     164  		perror_msg_and_fail("open: %s", tmp);
     165  
     166  	static const char w_c[] = "0123456789abcde";
     167  	const unsigned int w_len = LENGTH_OF(w_c);
     168  	const char *w_d = hexdump_strdup(w_c);
     169  	const void *w = tail_memdup(w_c, w_len);
     170  
     171  	static const char r0_c[] = "01234567";
     172  	const char *r0_d = hexdump_strdup(r0_c);
     173  	const unsigned int r0_len = (w_len + 1) / 2;
     174  	void *r0 = tail_alloc(r0_len);
     175  
     176  	static const char r1_c[] = "89abcde";
     177  	const char *r1_d = hexdump_strdup(r1_c);
     178  	const unsigned int r1_len = w_len - r0_len;
     179  	void *r1 = tail_alloc(w_len);
     180  
     181  	void *efault = r1 - get_page_size();
     182  
     183  	rc = k_write(1, w, 0);
     184  	if (rc)
     185  		perror_msg_and_fail("write: expected 0, returned %ld", rc);
     186  	tprintf("write(1, \"\", 0) = 0\n");
     187  
     188  	rc = k_write(1, efault, 1);
     189  	if (rc != -1)
     190  		perror_msg_and_fail("write: expected -1 EFAULT"
     191  				    ", returned %ld", rc);
     192  	tprintf("write(1, %p, 1) = -1 EFAULT (%m)\n", efault);
     193  
     194  	rc = k_write(1, w, w_len);
     195  	if (rc != (int) w_len)
     196  		perror_msg_and_fail("write: expected %u, returned %ld",
     197  				    w_len, rc);
     198  	tprintf("write(1, \"%s\", %u) = %ld\n"
     199  		" | 00000 %-49s  %-16s |\n",
     200  		w_c, w_len, rc, w_d, w_c);
     201  
     202  	rc = k_read(0, r0, 0);
     203  	if (rc)
     204  		perror_msg_and_fail("read: expected 0, returned %ld", rc);
     205  	tprintf("read(0, \"\", 0) = 0\n");
     206  
     207  	rc = k_read(0, efault, 1);
     208  	if (rc != -1)
     209  		perror_msg_and_fail("read: expected -1, returned %ld", rc);
     210  	tprintf("read(0, %p, 1) = -1 EFAULT (%m)\n", efault);
     211  
     212  	rc = k_read(0, r0, r0_len);
     213  	if (rc != (int) r0_len)
     214  		perror_msg_and_fail("read: expected %u, returned %ld",
     215  				    r0_len, rc);
     216  	tprintf("read(0, \"%s\", %u) = %ld\n"
     217  		" | 00000 %-49s  %-16s |\n",
     218  		r0_c, r0_len, rc, r0_d, r0_c);
     219  
     220  	rc = k_read(0, r1, w_len);
     221  	if (rc != (int) r1_len)
     222  		perror_msg_and_fail("read: expected %u, returned %ld",
     223  				    r1_len, rc);
     224  	tprintf("read(0, \"%s\", %u) = %ld\n"
     225  		" | 00000 %-49s  %-16s |\n",
     226  		r1_c, w_len, rc, r1_d, r1_c);
     227  	close(0);
     228  
     229  	/*
     230  	 * Check partial dump; relies on dumpstr() implementation details
     231  	 * (maximum size of chunk to be copied at once).
     232  	 */
     233  	static const size_t six_wide_size = 1 << 20;
     234  	static const size_t fetch_size = 1 << 16;
     235  	static const char big_buf_str[] =
     236  		"\\0\\1\\2\\3\\4\\5\\6\\7"
     237  		"\\10\\t\\n\\v\\f\\r\\16\\17"
     238  		"\\20\\21\\22\\23\\24\\25\\26\\27"
     239  		"\\30\\31\\32\\33\\34\\35\\36\\37";
     240  	const size_t buf_size = six_wide_size + fetch_size;
     241  	const size_t sizes[] = {
     242  		six_wide_size,
     243  		six_wide_size + 1,
     244  		buf_size,
     245  		buf_size + 1,
     246  		buf_size + 2,
     247  	};
     248  	char *big_buf = tail_alloc(buf_size);
     249  
     250  	fill_memory_ex(big_buf, buf_size, 0, 0x100);
     251  
     252  	for (size_t i = 0; i < ARRAY_SIZE(sizes); i++) {
     253  		rc = k_write(1, big_buf, sizes[i]);
     254  		tprintf("write(1, \"%s\"..., %zu) = %s\n",
     255  			big_buf_str, sizes[i], sprintrc(rc));
     256  		dump_str_ex(big_buf, MIN(sizes[i], buf_size),
     257  			    sizes[i] > six_wide_size ? 6 : 5);
     258  
     259  		if (sizes[i] == buf_size + 1)
     260  			tprintf(" | <Cannot fetch 1 byte from pid %d @%p>\n",
     261  				getpid(), big_buf + buf_size);
     262  
     263  		if (sizes[i] == buf_size + 2)
     264  			tprintf(" | <Cannot fetch 2 bytes from pid %d @%p>\n",
     265  				getpid(), big_buf + buf_size);
     266  	}
     267  
     268  	close(1);
     269  
     270  	if (open("/dev/zero", O_RDONLY))
     271  		perror_msg_and_fail("open");
     272  
     273  	if (open("/dev/null", O_WRONLY) != 1)
     274  		perror_msg_and_fail("open");
     275  
     276  	(void) close(4);
     277  	if (open("/dev/zero", O_RDONLY) != 4)
     278  		perror_msg_and_fail("open");
     279  
     280  	(void) close(5);
     281  	if (open("/dev/null", O_WRONLY) != 5)
     282  		perror_msg_and_fail("open");
     283  
     284  	for (unsigned int i = 0; i <= DEFAULT_STRLEN; ++i)
     285  		test_dump(i, false);
     286  
     287  	test_dump(256, true);
     288  
     289  	if (need_cleanup && unlink(tmp))
     290  		perror_msg_and_fail("unlink: %s", tmp);
     291  
     292  	tprintf("+++ exited with 0 +++\n");
     293  	return 0;
     294  }