Blob Blame History Raw
From e244ae965b17280313d92baef71165efc00ac51b Mon Sep 17 00:00:00 2001
From: "Dmitry V. Levin" <ldv@altlinux.org>
Date: Sat, 4 Jul 2020 08:00:00 +0000
Subject: [PATCH 144/149] tests: check decoding of faccessat syscall in -P, -y,
 and -yy modes

* tests/faccessat.c: Rewrite.
* tests/faccessat-P.c: New file.
* tests/faccessat-y.c: Likewise.
* tests/faccessat-yy.c: Likewise.
* tests/faccessat.test: New test.
* tests/Makefile.am (DECODER_TESTS): Add faccessat.test.
* tests/gen_tests.in (faccessat): Remove.
(faccessat-P, faccessat-y, faccessat-yy): New entries.
* tests/pure_executables.list: Add faccessat-P, faccessat-y,
and faccessat-yy.
* tests/.gitignore: Likewise.
---
 tests/.gitignore            |   3 ++
 tests/Makefile.am           |   1 +
 tests/faccessat-P.c         |   4 ++
 tests/faccessat-y.c         |   4 ++
 tests/faccessat-yy.c        |   4 ++
 tests/faccessat.c           | 127 ++++++++++++++++++++++++++++++++++++++++++--
 tests/faccessat.test        |  19 +++++++
 tests/gen_tests.in          |   4 +-
 tests/pure_executables.list |   3 ++
 9 files changed, 163 insertions(+), 6 deletions(-)
 create mode 100644 tests/faccessat-P.c
 create mode 100644 tests/faccessat-y.c
 create mode 100644 tests/faccessat-yy.c
 create mode 100755 tests/faccessat.test

Index: strace-5.7/tests/Makefile.am
===================================================================
--- strace-5.7.orig/tests/Makefile.am	2021-08-24 19:42:16.041519983 +0200
+++ strace-5.7/tests/Makefile.am	2021-08-24 19:46:08.275554370 +0200
@@ -346,6 +346,7 @@
 	execve-v.test \
 	execve.test \
 	fadvise64.test \
+	faccessat.test \
 	futex.test \
 	getuid.test \
 	int_0x80.test \
Index: strace-5.7/tests/faccessat-P.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ strace-5.7/tests/faccessat-P.c	2021-08-24 19:46:08.275554370 +0200
@@ -0,0 +1,4 @@
+#define PATH_TRACING
+#define SKIP_IF_PROC_IS_UNAVAILABLE skip_if_unavailable("/proc/self/fd/")
+
+#include "faccessat.c"
Index: strace-5.7/tests/faccessat-y.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ strace-5.7/tests/faccessat-y.c	2021-08-24 19:46:08.276554362 +0200
@@ -0,0 +1,4 @@
+#define FD_PATH "</dev/full>"
+#define SKIP_IF_PROC_IS_UNAVAILABLE skip_if_unavailable("/proc/self/fd/")
+
+#include "faccessat.c"
Index: strace-5.7/tests/faccessat-yy.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ strace-5.7/tests/faccessat-yy.c	2021-08-24 19:46:08.276554362 +0200
@@ -0,0 +1,4 @@
+#define FD_PATH "</dev/full<char 1:7>>"
+#define SKIP_IF_PROC_IS_UNAVAILABLE skip_if_unavailable("/proc/self/fd/")
+
+#include "faccessat.c"
Index: strace-5.7/tests/faccessat.c
===================================================================
--- strace-5.7.orig/tests/faccessat.c	2021-08-24 17:01:53.365934740 +0200
+++ strace-5.7/tests/faccessat.c	2021-08-24 19:46:08.277554353 +0200
@@ -1,4 +1,6 @@
 /*
+ * Check decoding of faccessat syscall.
+ *
  * Copyright (c) 2016-2019 The strace developers.
  * All rights reserved.
  *
@@ -10,18 +12,133 @@
 
 #ifdef __NR_faccessat
 
+# include <fcntl.h>
 # include <stdio.h>
 # include <unistd.h>
 
+# ifndef FD_PATH
+#  define FD_PATH ""
+# endif
+# ifndef SKIP_IF_PROC_IS_UNAVAILABLE
+#  define SKIP_IF_PROC_IS_UNAVAILABLE
+# endif
+
+static const char *errstr;
+
+static long
+k_faccessat(const unsigned int dirfd,
+	    const void *const pathname,
+	    const unsigned int mode)
+{
+	const kernel_ulong_t fill = (kernel_ulong_t) 0xdefaced00000000ULL;
+	const kernel_ulong_t bad = (kernel_ulong_t) 0xbadc0dedbadc0dedULL;
+
+	const kernel_ulong_t arg1 = fill | dirfd;
+	const kernel_ulong_t arg2 = (uintptr_t) pathname;
+	const kernel_ulong_t arg3 = fill | mode;
+	const long rc = syscall(__NR_faccessat,
+				arg1, arg2, arg3, bad, bad, bad);
+	errstr = sprintrc(rc);
+	return rc;
+}
+
 int
 main(void)
 {
-	static const char sample[] = "faccessat.sample";
-	const long int fd = (long int) 0xdeadbeefffffffffULL;
+	SKIP_IF_PROC_IS_UNAVAILABLE;
 
-	long rc = syscall(__NR_faccessat, fd, sample, F_OK);
-	printf("faccessat(%d, \"%s\", F_OK) = %ld %s (%m)\n",
-	       (int) fd, sample, rc, errno2name());
+	TAIL_ALLOC_OBJECT_CONST_PTR(const char, unterminated);
+	char *unterminated_str;
+	if (asprintf(&unterminated_str, "%p", unterminated) < 0)
+                perror_msg_and_fail("asprintf");
+	const void *const efault = unterminated + 1;
+	char *efault_str;
+	if (asprintf(&efault_str, "%p", efault) < 0)
+                perror_msg_and_fail("asprintf");
+
+	typedef struct {
+		char sym;
+		char null;
+	} sym_null;
+
+	TAIL_ALLOC_OBJECT_CONST_PTR(sym_null, dot);
+	dot->sym = '.';
+	dot->null = '\0';
+	const char *const null = &dot->null;
+
+	TAIL_ALLOC_OBJECT_CONST_PTR(sym_null, slash);
+	slash->sym = '/';
+	slash->null = '\0';
+
+	static const char path[] = "/dev/full";
+	const char *const fd_path = tail_memdup(path, sizeof(path));
+        int fd = open(path, O_WRONLY);
+        if (fd < 0)
+                perror_msg_and_fail("open: %s", path);
+	char *fd_str;
+	if (asprintf(&fd_str, "%d%s", fd, FD_PATH) < 0)
+                perror_msg_and_fail("asprintf");
+	char *path_quoted;
+	if (asprintf(&path_quoted, "\"%s\"", path) < 0)
+                perror_msg_and_fail("asprintf");
+
+	struct {
+		int val;
+		const char *str;
+	} dirfds[] = {
+		{ ARG_STR(-1) },
+		{ -100, "AT_FDCWD" },
+		{ fd, fd_str },
+	}, modes[] = {
+		{ ARG_STR(F_OK) },
+		{ ARG_STR(R_OK) },
+		{ ARG_STR(W_OK) },
+		{ ARG_STR(X_OK) },
+		{ ARG_STR(R_OK|W_OK) },
+		{ ARG_STR(R_OK|X_OK) },
+		{ ARG_STR(W_OK|X_OK) },
+		{ ARG_STR(R_OK|W_OK|X_OK) },
+		{ 8, "0x8 /* ?_OK */" },
+		{ -1, "R_OK|W_OK|X_OK|0xfffffff8" },
+	};
+
+	struct {
+		const void *val;
+		const char *str;
+	} paths[] = {
+		{ 0, "NULL" },
+		{ efault, efault_str },
+		{ unterminated, unterminated_str },
+		{ null, "\"\"" },
+		{ &dot->sym, "\".\"" },
+		{ &slash->sym, "\"/\"" },
+		{ fd_path, path_quoted },
+	};
+
+	for (unsigned int dirfd_i = 0;
+	     dirfd_i < ARRAY_SIZE(dirfds);
+	     ++dirfd_i) {
+		for (unsigned int path_i = 0;
+		     path_i < ARRAY_SIZE(paths);
+		     ++path_i) {
+			for (unsigned int mode_i = 0;
+			     mode_i < ARRAY_SIZE(modes);
+			     ++mode_i) {
+				k_faccessat(dirfds[dirfd_i].val,
+					    paths[path_i].val,
+					    modes[mode_i].val);
+# ifdef PATH_TRACING
+				if (dirfds[dirfd_i].val == fd ||
+				    paths[path_i].val == fd_path)
+# endif
+				printf("faccessat(%s, %s, %s) = %s\n",
+				       dirfds[dirfd_i].str,
+				       paths[path_i].str,
+				       modes[mode_i].str,
+				       errstr);
+			}
+		}
+	}
 
 	puts("+++ exited with 0 +++");
 	return 0;
Index: strace-5.7/tests/faccessat.test
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ strace-5.7/tests/faccessat.test	2021-08-24 19:46:08.277554353 +0200
@@ -0,0 +1,19 @@
+#!/bin/sh
+#
+# Check decoding of faccessat syscall.
+#
+# Copyright (c) 2020 Dmitry V. Levin <ldv@altlinux.org>
+# All rights reserved.
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+. "${srcdir=.}/init.sh"
+
+check_prog sed
+
+run_prog > /dev/null
+run_strace -a23 --trace=faccessat "$@" $args > "$EXP"
+
+# Filter out faccessat() calls made by ld.so and libc.
+sed -n '/^faccessat(-1, NULL,/,$p' < "$LOG" > "$OUT"
+match_diff "$OUT" "$EXP"
Index: strace-5.7/tests/gen_tests.in
===================================================================
--- strace-5.7.orig/tests/gen_tests.in	2021-08-24 19:37:43.192829355 +0200
+++ strace-5.7/tests/gen_tests.in	2021-08-24 19:46:08.278554345 +0200
@@ -73,7 +73,9 @@
 erestartsys	-a34 -e signal=none -e trace=recvfrom
 execveat
 execveat-v	-v -e trace=execveat
-faccessat	-P $NAME.sample
+faccessat-P	-a23 --trace=faccessat -P /dev/full
+faccessat-y	+faccessat.test -a24 -y
+faccessat-yy	+faccessat.test -a24 -yy
 fadvise64_64	+fadvise64.test
 fallocate	-a18
 fanotify_init
Index: strace-5.7/tests/pure_executables.list
===================================================================
--- strace-5.7.orig/tests/pure_executables.list	2021-08-24 19:37:43.192829355 +0200
+++ strace-5.7/tests/pure_executables.list	2021-08-24 19:46:08.279554336 +0200
@@ -61,6 +61,9 @@
 execve
 execveat
 faccessat
+faccessat-P
+faccessat-y
+faccessat-yy
 fadvise64
 fadvise64_64
 fallocate
Index: strace-5.7/tests-m32/Makefile.am
===================================================================
--- strace-5.7.orig/tests-m32/Makefile.am	2021-08-24 19:42:16.045519949 +0200
+++ strace-5.7/tests-m32/Makefile.am	2021-08-24 19:46:08.279554336 +0200
@@ -346,6 +346,7 @@
 	execve-v.test \
 	execve.test \
 	fadvise64.test \
+	faccessat.test \
 	futex.test \
 	getuid.test \
 	int_0x80.test \
Index: strace-5.7/tests-m32/faccessat-P.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ strace-5.7/tests-m32/faccessat-P.c	2021-08-24 19:46:08.279554336 +0200
@@ -0,0 +1,4 @@
+#define PATH_TRACING
+#define SKIP_IF_PROC_IS_UNAVAILABLE skip_if_unavailable("/proc/self/fd/")
+
+#include "faccessat.c"
Index: strace-5.7/tests-m32/faccessat-y.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ strace-5.7/tests-m32/faccessat-y.c	2021-08-24 19:46:08.280554328 +0200
@@ -0,0 +1,4 @@
+#define FD_PATH "</dev/full>"
+#define SKIP_IF_PROC_IS_UNAVAILABLE skip_if_unavailable("/proc/self/fd/")
+
+#include "faccessat.c"
Index: strace-5.7/tests-m32/faccessat-yy.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ strace-5.7/tests-m32/faccessat-yy.c	2021-08-24 19:46:08.280554328 +0200
@@ -0,0 +1,4 @@
+#define FD_PATH "</dev/full<char 1:7>>"
+#define SKIP_IF_PROC_IS_UNAVAILABLE skip_if_unavailable("/proc/self/fd/")
+
+#include "faccessat.c"
Index: strace-5.7/tests-m32/faccessat.c
===================================================================
--- strace-5.7.orig/tests-m32/faccessat.c	2019-09-25 03:02:03.000000000 +0200
+++ strace-5.7/tests-m32/faccessat.c	2021-08-24 19:46:08.281554319 +0200
@@ -1,4 +1,6 @@
 /*
+ * Check decoding of faccessat syscall.
+ *
  * Copyright (c) 2016-2019 The strace developers.
  * All rights reserved.
  *
@@ -10,18 +12,133 @@
 
 #ifdef __NR_faccessat
 
+# include <fcntl.h>
 # include <stdio.h>
 # include <unistd.h>
 
+# ifndef FD_PATH
+#  define FD_PATH ""
+# endif
+# ifndef SKIP_IF_PROC_IS_UNAVAILABLE
+#  define SKIP_IF_PROC_IS_UNAVAILABLE
+# endif
+
+static const char *errstr;
+
+static long
+k_faccessat(const unsigned int dirfd,
+	    const void *const pathname,
+	    const unsigned int mode)
+{
+	const kernel_ulong_t fill = (kernel_ulong_t) 0xdefaced00000000ULL;
+	const kernel_ulong_t bad = (kernel_ulong_t) 0xbadc0dedbadc0dedULL;
+
+	const kernel_ulong_t arg1 = fill | dirfd;
+	const kernel_ulong_t arg2 = (uintptr_t) pathname;
+	const kernel_ulong_t arg3 = fill | mode;
+	const long rc = syscall(__NR_faccessat,
+				arg1, arg2, arg3, bad, bad, bad);
+	errstr = sprintrc(rc);
+	return rc;
+}
+
 int
 main(void)
 {
-	static const char sample[] = "faccessat.sample";
-	const long int fd = (long int) 0xdeadbeefffffffffULL;
+	SKIP_IF_PROC_IS_UNAVAILABLE;
 
-	long rc = syscall(__NR_faccessat, fd, sample, F_OK);
-	printf("faccessat(%d, \"%s\", F_OK) = %ld %s (%m)\n",
-	       (int) fd, sample, rc, errno2name());
+	TAIL_ALLOC_OBJECT_CONST_PTR(const char, unterminated);
+	char *unterminated_str;
+	if (asprintf(&unterminated_str, "%p", unterminated) < 0)
+                perror_msg_and_fail("asprintf");
+	const void *const efault = unterminated + 1;
+	char *efault_str;
+	if (asprintf(&efault_str, "%p", efault) < 0)
+                perror_msg_and_fail("asprintf");
+
+	typedef struct {
+		char sym;
+		char null;
+	} sym_null;
+
+	TAIL_ALLOC_OBJECT_CONST_PTR(sym_null, dot);
+	dot->sym = '.';
+	dot->null = '\0';
+	const char *const null = &dot->null;
+
+	TAIL_ALLOC_OBJECT_CONST_PTR(sym_null, slash);
+	slash->sym = '/';
+	slash->null = '\0';
+
+	static const char path[] = "/dev/full";
+	const char *const fd_path = tail_memdup(path, sizeof(path));
+        int fd = open(path, O_WRONLY);
+        if (fd < 0)
+                perror_msg_and_fail("open: %s", path);
+	char *fd_str;
+	if (asprintf(&fd_str, "%d%s", fd, FD_PATH) < 0)
+                perror_msg_and_fail("asprintf");
+	char *path_quoted;
+	if (asprintf(&path_quoted, "\"%s\"", path) < 0)
+                perror_msg_and_fail("asprintf");
+
+	struct {
+		int val;
+		const char *str;
+	} dirfds[] = {
+		{ ARG_STR(-1) },
+		{ -100, "AT_FDCWD" },
+		{ fd, fd_str },
+	}, modes[] = {
+		{ ARG_STR(F_OK) },
+		{ ARG_STR(R_OK) },
+		{ ARG_STR(W_OK) },
+		{ ARG_STR(X_OK) },
+		{ ARG_STR(R_OK|W_OK) },
+		{ ARG_STR(R_OK|X_OK) },
+		{ ARG_STR(W_OK|X_OK) },
+		{ ARG_STR(R_OK|W_OK|X_OK) },
+		{ 8, "0x8 /* ?_OK */" },
+		{ -1, "R_OK|W_OK|X_OK|0xfffffff8" },
+	};
+
+	struct {
+		const void *val;
+		const char *str;
+	} paths[] = {
+		{ 0, "NULL" },
+		{ efault, efault_str },
+		{ unterminated, unterminated_str },
+		{ null, "\"\"" },
+		{ &dot->sym, "\".\"" },
+		{ &slash->sym, "\"/\"" },
+		{ fd_path, path_quoted },
+	};
+
+	for (unsigned int dirfd_i = 0;
+	     dirfd_i < ARRAY_SIZE(dirfds);
+	     ++dirfd_i) {
+		for (unsigned int path_i = 0;
+		     path_i < ARRAY_SIZE(paths);
+		     ++path_i) {
+			for (unsigned int mode_i = 0;
+			     mode_i < ARRAY_SIZE(modes);
+			     ++mode_i) {
+				k_faccessat(dirfds[dirfd_i].val,
+					    paths[path_i].val,
+					    modes[mode_i].val);
+# ifdef PATH_TRACING
+				if (dirfds[dirfd_i].val == fd ||
+				    paths[path_i].val == fd_path)
+# endif
+				printf("faccessat(%s, %s, %s) = %s\n",
+				       dirfds[dirfd_i].str,
+				       paths[path_i].str,
+				       modes[mode_i].str,
+				       errstr);
+			}
+		}
+	}
 
 	puts("+++ exited with 0 +++");
 	return 0;
Index: strace-5.7/tests-m32/faccessat.test
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ strace-5.7/tests-m32/faccessat.test	2021-08-24 19:46:08.281554319 +0200
@@ -0,0 +1,19 @@
+#!/bin/sh
+#
+# Check decoding of faccessat syscall.
+#
+# Copyright (c) 2020 Dmitry V. Levin <ldv@altlinux.org>
+# All rights reserved.
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+. "${srcdir=.}/init.sh"
+
+check_prog sed
+
+run_prog > /dev/null
+run_strace -a23 --trace=faccessat "$@" $args > "$EXP"
+
+# Filter out faccessat() calls made by ld.so and libc.
+sed -n '/^faccessat(-1, NULL,/,$p' < "$LOG" > "$OUT"
+match_diff "$OUT" "$EXP"
Index: strace-5.7/tests-m32/gen_tests.in
===================================================================
--- strace-5.7.orig/tests-m32/gen_tests.in	2021-08-24 19:37:43.193829347 +0200
+++ strace-5.7/tests-m32/gen_tests.in	2021-08-24 19:46:08.282554311 +0200
@@ -73,7 +73,9 @@
 erestartsys	-a34 -e signal=none -e trace=recvfrom
 execveat
 execveat-v	-v -e trace=execveat
-faccessat	-P $NAME.sample
+faccessat-P	-a23 --trace=faccessat -P /dev/full
+faccessat-y	+faccessat.test -a24 -y
+faccessat-yy	+faccessat.test -a24 -yy
 fadvise64_64	+fadvise64.test
 fallocate	-a18
 fanotify_init
Index: strace-5.7/tests-m32/pure_executables.list
===================================================================
--- strace-5.7.orig/tests-m32/pure_executables.list	2021-08-24 19:37:43.193829347 +0200
+++ strace-5.7/tests-m32/pure_executables.list	2021-08-24 19:46:08.283554302 +0200
@@ -61,6 +61,9 @@
 execve
 execveat
 faccessat
+faccessat-P
+faccessat-y
+faccessat-yy
 fadvise64
 fadvise64_64
 fallocate
Index: strace-5.7/tests-mx32/Makefile.am
===================================================================
--- strace-5.7.orig/tests-mx32/Makefile.am	2021-08-24 19:42:16.048519924 +0200
+++ strace-5.7/tests-mx32/Makefile.am	2021-08-24 19:46:08.283554302 +0200
@@ -346,6 +346,7 @@
 	execve-v.test \
 	execve.test \
 	fadvise64.test \
+	faccessat.test \
 	futex.test \
 	getuid.test \
 	int_0x80.test \
Index: strace-5.7/tests-mx32/faccessat-P.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ strace-5.7/tests-mx32/faccessat-P.c	2021-08-24 19:46:08.283554302 +0200
@@ -0,0 +1,4 @@
+#define PATH_TRACING
+#define SKIP_IF_PROC_IS_UNAVAILABLE skip_if_unavailable("/proc/self/fd/")
+
+#include "faccessat.c"
Index: strace-5.7/tests-mx32/faccessat-y.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ strace-5.7/tests-mx32/faccessat-y.c	2021-08-24 19:46:08.284554294 +0200
@@ -0,0 +1,4 @@
+#define FD_PATH "</dev/full>"
+#define SKIP_IF_PROC_IS_UNAVAILABLE skip_if_unavailable("/proc/self/fd/")
+
+#include "faccessat.c"
Index: strace-5.7/tests-mx32/faccessat-yy.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ strace-5.7/tests-mx32/faccessat-yy.c	2021-08-24 19:46:08.284554294 +0200
@@ -0,0 +1,4 @@
+#define FD_PATH "</dev/full<char 1:7>>"
+#define SKIP_IF_PROC_IS_UNAVAILABLE skip_if_unavailable("/proc/self/fd/")
+
+#include "faccessat.c"
Index: strace-5.7/tests-mx32/faccessat.c
===================================================================
--- strace-5.7.orig/tests-mx32/faccessat.c	2019-09-25 03:02:03.000000000 +0200
+++ strace-5.7/tests-mx32/faccessat.c	2021-08-24 19:46:08.285554285 +0200
@@ -1,4 +1,6 @@
 /*
+ * Check decoding of faccessat syscall.
+ *
  * Copyright (c) 2016-2019 The strace developers.
  * All rights reserved.
  *
@@ -10,18 +12,133 @@
 
 #ifdef __NR_faccessat
 
+# include <fcntl.h>
 # include <stdio.h>
 # include <unistd.h>
 
+# ifndef FD_PATH
+#  define FD_PATH ""
+# endif
+# ifndef SKIP_IF_PROC_IS_UNAVAILABLE
+#  define SKIP_IF_PROC_IS_UNAVAILABLE
+# endif
+
+static const char *errstr;
+
+static long
+k_faccessat(const unsigned int dirfd,
+	    const void *const pathname,
+	    const unsigned int mode)
+{
+	const kernel_ulong_t fill = (kernel_ulong_t) 0xdefaced00000000ULL;
+	const kernel_ulong_t bad = (kernel_ulong_t) 0xbadc0dedbadc0dedULL;
+
+	const kernel_ulong_t arg1 = fill | dirfd;
+	const kernel_ulong_t arg2 = (uintptr_t) pathname;
+	const kernel_ulong_t arg3 = fill | mode;
+	const long rc = syscall(__NR_faccessat,
+				arg1, arg2, arg3, bad, bad, bad);
+	errstr = sprintrc(rc);
+	return rc;
+}
+
 int
 main(void)
 {
-	static const char sample[] = "faccessat.sample";
-	const long int fd = (long int) 0xdeadbeefffffffffULL;
+	SKIP_IF_PROC_IS_UNAVAILABLE;
 
-	long rc = syscall(__NR_faccessat, fd, sample, F_OK);
-	printf("faccessat(%d, \"%s\", F_OK) = %ld %s (%m)\n",
-	       (int) fd, sample, rc, errno2name());
+	TAIL_ALLOC_OBJECT_CONST_PTR(const char, unterminated);
+	char *unterminated_str;
+	if (asprintf(&unterminated_str, "%p", unterminated) < 0)
+                perror_msg_and_fail("asprintf");
+	const void *const efault = unterminated + 1;
+	char *efault_str;
+	if (asprintf(&efault_str, "%p", efault) < 0)
+                perror_msg_and_fail("asprintf");
+
+	typedef struct {
+		char sym;
+		char null;
+	} sym_null;
+
+	TAIL_ALLOC_OBJECT_CONST_PTR(sym_null, dot);
+	dot->sym = '.';
+	dot->null = '\0';
+	const char *const null = &dot->null;
+
+	TAIL_ALLOC_OBJECT_CONST_PTR(sym_null, slash);
+	slash->sym = '/';
+	slash->null = '\0';
+
+	static const char path[] = "/dev/full";
+	const char *const fd_path = tail_memdup(path, sizeof(path));
+        int fd = open(path, O_WRONLY);
+        if (fd < 0)
+                perror_msg_and_fail("open: %s", path);
+	char *fd_str;
+	if (asprintf(&fd_str, "%d%s", fd, FD_PATH) < 0)
+                perror_msg_and_fail("asprintf");
+	char *path_quoted;
+	if (asprintf(&path_quoted, "\"%s\"", path) < 0)
+                perror_msg_and_fail("asprintf");
+
+	struct {
+		int val;
+		const char *str;
+	} dirfds[] = {
+		{ ARG_STR(-1) },
+		{ -100, "AT_FDCWD" },
+		{ fd, fd_str },
+	}, modes[] = {
+		{ ARG_STR(F_OK) },
+		{ ARG_STR(R_OK) },
+		{ ARG_STR(W_OK) },
+		{ ARG_STR(X_OK) },
+		{ ARG_STR(R_OK|W_OK) },
+		{ ARG_STR(R_OK|X_OK) },
+		{ ARG_STR(W_OK|X_OK) },
+		{ ARG_STR(R_OK|W_OK|X_OK) },
+		{ 8, "0x8 /* ?_OK */" },
+		{ -1, "R_OK|W_OK|X_OK|0xfffffff8" },
+	};
+
+	struct {
+		const void *val;
+		const char *str;
+	} paths[] = {
+		{ 0, "NULL" },
+		{ efault, efault_str },
+		{ unterminated, unterminated_str },
+		{ null, "\"\"" },
+		{ &dot->sym, "\".\"" },
+		{ &slash->sym, "\"/\"" },
+		{ fd_path, path_quoted },
+	};
+
+	for (unsigned int dirfd_i = 0;
+	     dirfd_i < ARRAY_SIZE(dirfds);
+	     ++dirfd_i) {
+		for (unsigned int path_i = 0;
+		     path_i < ARRAY_SIZE(paths);
+		     ++path_i) {
+			for (unsigned int mode_i = 0;
+			     mode_i < ARRAY_SIZE(modes);
+			     ++mode_i) {
+				k_faccessat(dirfds[dirfd_i].val,
+					    paths[path_i].val,
+					    modes[mode_i].val);
+# ifdef PATH_TRACING
+				if (dirfds[dirfd_i].val == fd ||
+				    paths[path_i].val == fd_path)
+# endif
+				printf("faccessat(%s, %s, %s) = %s\n",
+				       dirfds[dirfd_i].str,
+				       paths[path_i].str,
+				       modes[mode_i].str,
+				       errstr);
+			}
+		}
+	}
 
 	puts("+++ exited with 0 +++");
 	return 0;
Index: strace-5.7/tests-mx32/faccessat.test
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ strace-5.7/tests-mx32/faccessat.test	2021-08-24 19:46:08.285554285 +0200
@@ -0,0 +1,19 @@
+#!/bin/sh
+#
+# Check decoding of faccessat syscall.
+#
+# Copyright (c) 2020 Dmitry V. Levin <ldv@altlinux.org>
+# All rights reserved.
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+. "${srcdir=.}/init.sh"
+
+check_prog sed
+
+run_prog > /dev/null
+run_strace -a23 --trace=faccessat "$@" $args > "$EXP"
+
+# Filter out faccessat() calls made by ld.so and libc.
+sed -n '/^faccessat(-1, NULL,/,$p' < "$LOG" > "$OUT"
+match_diff "$OUT" "$EXP"
Index: strace-5.7/tests-mx32/gen_tests.in
===================================================================
--- strace-5.7.orig/tests-mx32/gen_tests.in	2021-08-24 19:37:43.194829339 +0200
+++ strace-5.7/tests-mx32/gen_tests.in	2021-08-24 19:46:08.286554277 +0200
@@ -73,7 +73,9 @@
 erestartsys	-a34 -e signal=none -e trace=recvfrom
 execveat
 execveat-v	-v -e trace=execveat
-faccessat	-P $NAME.sample
+faccessat-P	-a23 --trace=faccessat -P /dev/full
+faccessat-y	+faccessat.test -a24 -y
+faccessat-yy	+faccessat.test -a24 -yy
 fadvise64_64	+fadvise64.test
 fallocate	-a18
 fanotify_init
Index: strace-5.7/tests-mx32/pure_executables.list
===================================================================
--- strace-5.7.orig/tests-mx32/pure_executables.list	2021-08-24 19:37:43.195829330 +0200
+++ strace-5.7/tests-mx32/pure_executables.list	2021-08-24 19:46:08.286554277 +0200
@@ -61,6 +61,9 @@
 execve
 execveat
 faccessat
+faccessat-P
+faccessat-y
+faccessat-yy
 fadvise64
 fadvise64_64
 fallocate
Index: strace-5.7/tests/Makefile.in
===================================================================
--- strace-5.7.orig/tests/Makefile.in	2021-08-24 19:42:54.720192609 +0200
+++ strace-5.7/tests/Makefile.in	2021-08-24 19:46:08.292554226 +0200
@@ -6523,6 +6523,7 @@
 	execve-v.test \
 	execve.test \
 	fadvise64.test \
+	faccessat.test \
 	futex.test \
 	getuid.test \
 	int_0x80.test \
Index: strace-5.7/tests-m32/Makefile.in
===================================================================
--- strace-5.7.orig/tests-m32/Makefile.in	2021-08-24 19:43:13.669032228 +0200
+++ strace-5.7/tests-m32/Makefile.in	2021-08-24 19:46:08.296554192 +0200
@@ -6523,6 +6523,7 @@
 	execve-v.test \
 	execve.test \
 	fadvise64.test \
+	faccessat.test \
 	futex.test \
 	getuid.test \
 	int_0x80.test \
Index: strace-5.7/tests-mx32/Makefile.in
===================================================================
--- strace-5.7.orig/tests-mx32/Makefile.in	2021-08-24 19:43:32.469873099 +0200
+++ strace-5.7/tests-mx32/Makefile.in	2021-08-24 19:46:08.299554167 +0200
@@ -6523,6 +6523,7 @@
 	execve-v.test \
 	execve.test \
 	fadvise64.test \
+	faccessat.test \
 	futex.test \
 	getuid.test \
 	int_0x80.test \