[PATCH v3 2/2] decode-fds: add signalfd fdinfo decoding support

leedagee leedageea at gmail.com
Wed Mar 29 14:09:13 UTC 2023


When signalfds are used, normal signal handling method is ususally
disabled, leaving strace without signals to catch and decode.

This patch adds decoding of signal masks associated with signalfd file
descriptors.

Decoding the signalfd_siginfo struct requires additional work mentioned
in github#199.

Signed-off-by: leedagee <leedageea at gmail.com>
---
 NEWS                        |  2 ++
 doc/strace.1.in             |  5 ++++-
 src/filter_qualify.c        |  1 +
 src/number_set.h            |  1 +
 src/strace.c                |  3 ++-
 src/util.c                  | 44 +++++++++++++++++++++++++++++++++++++
 tests/.gitignore            |  1 +
 tests/gen_tests.in          |  3 ++-
 tests/pure_executables.list |  1 +
 tests/signalfd4-yy.c        |  4 ++++
 tests/signalfd4.c           | 35 +++++++++++++++++++++++++----
 11 files changed, 93 insertions(+), 7 deletions(-)
 create mode 100644 tests/signalfd4-yy.c

diff --git a/NEWS b/NEWS
index fa56409ba..ce39fe2ab 100644
--- a/NEWS
+++ b/NEWS
@@ -2,6 +2,8 @@ Noteworthy changes in release ?.? (????-??-??)
 ==============================================
 
 * Improvements
+  * Implemented decoding of signal masks associated with signalfd
+    file descriptors.
 
 Noteworthy changes in release 6.2 (2023-02-26)
 ==============================================
diff --git a/doc/strace.1.in b/doc/strace.1.in
index 71661bd2e..38c10ad99 100644
--- a/doc/strace.1.in
+++ b/doc/strace.1.in
@@ -888,7 +888,7 @@ Decode various information associated with file descriptors.  The default is
 .I set
 can include the following elements:
 .RS
-.TP 8
+.TP 9
 .B path
 Print file paths.
 Also enables printing of tracee's current working directory when
@@ -903,6 +903,9 @@ Print character/block device numbers.
 .TQ
 .B pidfd
 Print PIDs associated with pidfd file descriptors.
+.TQ
+.B signalfd
+Print signal masks associated with signalfd file descriptors.
 .RE
 .TP
 \fB\-e\ decode\-pids\fR=\,\fIset\fR
diff --git a/src/filter_qualify.c b/src/filter_qualify.c
index c3bf2e9ad..c15a68bd3 100644
--- a/src/filter_qualify.c
+++ b/src/filter_qualify.c
@@ -105,6 +105,7 @@ decode_fd_str_to_uint(const char *str)
 		{ DECODE_FD_SOCKET,    "socket" },
 		{ DECODE_FD_DEV,       "dev" },
 		{ DECODE_FD_PIDFD,     "pidfd" },
+		{ DECODE_FD_SIGNALFD,  "signalfd" },
 	};
 
 	return (int) find_arg_val(str, decode_fd_strs, -1ULL, -1ULL);
diff --git a/src/number_set.h b/src/number_set.h
index 5cd030f7c..d4bfb1405 100644
--- a/src/number_set.h
+++ b/src/number_set.h
@@ -76,6 +76,7 @@ enum decode_fd_bits {
 	DECODE_FD_SOCKET,
 	DECODE_FD_DEV,
 	DECODE_FD_PIDFD,
+	DECODE_FD_SIGNALFD,
 
 	NUM_DECODE_FD_BITS
 };
diff --git a/src/strace.c b/src/strace.c
index 21b693d02..4f81f3997 100644
--- a/src/strace.c
+++ b/src/strace.c
@@ -365,7 +365,8 @@ Output format:\n\
      details:    dev (device major/minor for block/char device files)\n\
                  path (file path),\n\
                  pidfd (associated PID for pidfds),\n\
-                 socket (protocol-specific information for socket descriptors)\n\
+                 socket (protocol-specific information for socket descriptors),\n\
+                 signalfd (signal masks for signalfds)\n\
 "
 #ifdef ENABLE_SECONTEXT
 "\
diff --git a/src/util.c b/src/util.c
index f3013ec64..8d333c358 100644
--- a/src/util.c
+++ b/src/util.c
@@ -784,6 +784,47 @@ printpidfd(pid_t pid_of_fd, int fd, const char *path)
 	return true;
 }
 
+static bool
+printsignalfd(pid_t pid, int fd, const char *path)
+{
+	static const char signalfd_path[] = "anon_inode:[signalfd]";
+	static const char sigmask_pfx[] = "sigmask:\t";
+
+	if (strcmp(path, signalfd_path))
+		return false;
+
+	char *result = search_fdinfo(pid, fd, sigmask_pfx, sizeof(sigmask_pfx) - 1);
+
+	if (result == NULL)
+		return false;
+
+	size_t sigset_size = strlen(result) / 2;
+	char *sigmask = xmalloc(sigset_size);
+
+	for (size_t i = 0; i < sigset_size; i++) {
+		if (sscanf(result + i * 2, "%02hhx", sigmask +
+#ifndef WORDS_BIGENDIAN
+			     sigset_size - 1 -
+#endif
+			     i) != 1) {
+			free(sigmask);
+			free(result);
+
+			return false;
+		}
+	}
+
+	free(result);
+
+	tprint_associated_info_begin();
+	tprints_string(sprintsigmask_n("signalfd:", sigmask, sigset_size));
+	tprint_associated_info_end();
+
+	free(sigmask);
+
+	return true;
+}
+
 static void
 print_quoted_string_in_angle_brackets(const char *str, const bool deleted)
 {
@@ -815,6 +856,9 @@ printfd_pid_with_finfo(struct tcb *tcp, pid_t pid, int fd, const struct finfo *f
 		if (is_number_in_set(DECODE_FD_PIDFD, decode_fd_set) &&
 		    printpidfd(pid, fd, path))
 			goto printed;
+		if (is_number_in_set(DECODE_FD_SIGNALFD, decode_fd_set) &&
+		    printsignalfd(pid, fd, path))
+			goto printed;
 		if (is_number_in_set(DECODE_FD_PATH, decode_fd_set))
 			print_quoted_string_in_angle_brackets(path,
 							      finfo? finfo->deleted: deleted);
diff --git a/tests/.gitignore b/tests/.gitignore
index 5935c39d9..3548b8209 100644
--- a/tests/.gitignore
+++ b/tests/.gitignore
@@ -958,6 +958,7 @@ signal
 signal_receive
 signal_receive--pidns-translation
 signalfd4
+signalfd4-yy
 sigpending
 sigprocmask
 sigreturn
diff --git a/tests/gen_tests.in b/tests/gen_tests.in
index eceac8d60..3c4710b0b 100644
--- a/tests/gen_tests.in
+++ b/tests/gen_tests.in
@@ -936,7 +936,8 @@ siginfo	-e trace=none
 signal	-a25 -e signal=none -e trace='/^signal$'
 signal_receive	-a16 -e trace=kill
 signal_receive--pidns-translation	test_pidns -a16 -e trace=kill
-signalfd4
+signalfd4	-a10
+signalfd4-yy	--trace=signalfd4 -yy
 sigpending	-a15
 sigprocmask	-a34
 sigreturn	-esignal='!USR1'
diff --git a/tests/pure_executables.list b/tests/pure_executables.list
index db527ee7b..c9ccdeefb 100755
--- a/tests/pure_executables.list
+++ b/tests/pure_executables.list
@@ -683,6 +683,7 @@ sigaltstack
 siginfo
 signal
 signalfd4
+signalfd4-yy
 sigpending
 sigprocmask
 sigreturn
diff --git a/tests/signalfd4-yy.c b/tests/signalfd4-yy.c
new file mode 100644
index 000000000..6a5262628
--- /dev/null
+++ b/tests/signalfd4-yy.c
@@ -0,0 +1,4 @@
+#define SKIP_IF_PROC_IS_UNAVAILABLE skip_if_unavailable("/proc/self/fd/")
+#define PRINT_SIGNALFD
+
+#include "signalfd4.c"
diff --git a/tests/signalfd4.c b/tests/signalfd4.c
index e45e9425c..97e7977a2 100644
--- a/tests/signalfd4.c
+++ b/tests/signalfd4.c
@@ -20,20 +20,47 @@
 # include <sys/signalfd.h>
 # include "kernel_fcntl.h"
 
+#ifndef SKIP_IF_PROC_IS_UNAVAILABLE
+# define SKIP_IF_PROC_IS_UNAVAILABLE
+#endif
+
 int
 main(void)
 {
-	const char *const sigs = SIGUSR2 < SIGCHLD ? "USR2 CHLD" : "CHLD USR2";
+	SKIP_IF_PROC_IS_UNAVAILABLE;
+
+	const char *const sigs1 = "USR2";
+	const char *const sigs2 = SIGUSR2 < SIGCHLD ? "USR2 CHLD" : "CHLD USR2";
 	const unsigned int size = get_sigset_size();
 
 	sigset_t mask;
 	sigemptyset(&mask);
 	sigaddset(&mask, SIGUSR2);
+
+	int fd = signalfd(-1, &mask, SFD_CLOEXEC | SFD_NONBLOCK);
+
+#ifdef PRINT_SIGNALFD
+	if (fd == -1)
+		perror_msg_and_skip("signalfd");
+#endif
+
+	printf("signalfd4(-1, [%s], %u, SFD_CLOEXEC|SFD_NONBLOCK) = %s",
+	       sigs1, size, sprintrc(fd));
+#ifdef PRINT_SIGNALFD
+	printf("<signalfd:[%s]>\n", sigs1);
+#else
+	putchar('\n');
+#endif
+
 	sigaddset(&mask, SIGCHLD);
+	fd = signalfd(fd, &mask, 0);
 
-	int fd = signalfd(-1, &mask, O_CLOEXEC | O_NONBLOCK);
-	printf("signalfd4(-1, [%s], %u, SFD_CLOEXEC|SFD_NONBLOCK) = %s\n",
-	       sigs, size, sprintrc(fd));
+#ifdef PRINT_SIGNALFD
+	printf("signalfd4(%d<signalfd:[%s]>, [%s], %u, 0) = %s<signalfd:[%s]>\n",
+	       fd, sigs1, sigs2, size, sprintrc(fd), sigs2);
+#else
+	printf("signalfd4(%d, [%s], %u, 0) = %s\n", fd, sigs2, size, sprintrc(fd));
+#endif
 
 	puts("+++ exited with 0 +++");
 	return 0;
-- 
2.35.3



More information about the Strace-devel mailing list