Blame SOURCES/0134-PID-namespace-translation-support.patch

b4ec74
From bf533b84fd7200399c9b0e68fdf10c6aaf8b1a7a Mon Sep 17 00:00:00 2001
b4ec74
From: =?UTF-8?q?=C3=81kos=20Uzonyi?= <uzonyi.akos@gmail.com>
b4ec74
Date: Mon, 8 Jun 2020 19:01:03 +0200
b4ec74
Subject: [PATCH 134/138] PID namespace translation support
b4ec74
b4ec74
* defs.h (pidns_translation): New variable.
b4ec74
(tcb): Add pid_ns field.
b4ec74
(RVAL_MASK): Change value from 013 to 017.
b4ec74
(RVAL_TID, RVAL_SID, RVAL_TGID, RVAL_PGID): New definitions.
b4ec74
(pid_type): New enum.
b4ec74
(pidns_init, translate_pid, get_proc_pid, printpid, printpid_tgid_pgid):
b4ec74
New function declarations.
b4ec74
* largefile_wrappers.h (fstat_fd): New macro.
b4ec74
* pidns.c: New file.
b4ec74
* trie.c: New file.
b4ec74
* trie.h: New file.
b4ec74
* Makefile.am (libstrace_a_SOURCES): Add trie.c, trie.h, pidns.c.
b4ec74
* strace.c (pidns_translation): New variable.
b4ec74
(init): Add --pidns-translation option.
b4ec74
* syscall.c (syscall_exiting_trace): Handle RVAL_* return values.
b4ec74
* NEWS: Mention this.
b4ec74
* strace.1.in: Add description for new option.
b4ec74
b4ec74
Co-Authored-by: Eugene Syromyatnikov <evgsyr@gmail.com>
b4ec74
b4ec74
Conflicts:
b4ec74
	NEWS
b4ec74
---
b4ec74
 Makefile.am          |   3 +
b4ec74
 defs.h               |  56 ++++-
b4ec74
 largefile_wrappers.h |   2 +
b4ec74
 pidns.c              | 608 +++++++++++++++++++++++++++++++++++++++++++++++++++
b4ec74
 strace.1.in          |   4 +
b4ec74
 strace.c             |   9 +
b4ec74
 syscall.c            |  15 ++
b4ec74
 trie.c               | 290 ++++++++++++++++++++++++
b4ec74
 trie.h               |  92 ++++++++
b4ec74
 9 files changed, 1078 insertions(+), 1 deletion(-)
b4ec74
 create mode 100644 pidns.c
b4ec74
 create mode 100644 trie.c
b4ec74
 create mode 100644 trie.h
b4ec74
b4ec74
Index: strace-5.7/Makefile.am
b4ec74
===================================================================
b4ec74
--- strace-5.7.orig/Makefile.am	2020-09-09 15:50:13.471900510 +0200
b4ec74
+++ strace-5.7/Makefile.am	2020-09-09 15:52:09.159983257 +0200
b4ec74
@@ -233,6 +233,7 @@
b4ec74
 	personality.c	\
b4ec74
 	pidfd_getfd.c	\
b4ec74
 	pidfd_open.c	\
b4ec74
+	pidns.c		\
b4ec74
 	pkeys.c		\
b4ec74
 	poll.c		\
b4ec74
 	prctl.c		\
b4ec74
@@ -344,6 +345,8 @@
b4ec74
 	time.c		\
b4ec74
 	times.c		\
b4ec74
 	trace_event.h	\
b4ec74
+	trie.c 		\
b4ec74
+	trie.h 		\
b4ec74
 	truncate.c	\
b4ec74
 	ubi.c		\
b4ec74
 	ucopy.c		\
b4ec74
Index: strace-5.7/defs.h
b4ec74
===================================================================
b4ec74
--- strace-5.7.orig/defs.h	2020-09-09 15:50:13.473900511 +0200
b4ec74
+++ strace-5.7/defs.h	2020-09-09 15:52:09.159983257 +0200
b4ec74
@@ -280,6 +280,13 @@
b4ec74
 	struct timespec etime;	/* Syscall entry time (CLOCK_MONOTONIC) */
b4ec74
 	struct timespec delay_expiration_time; /* When does the delay end */
b4ec74
 
b4ec74
+	/*
b4ec74
+	 * The ID of the PID namespace of this process
b4ec74
+	 * (inode number of /proc/<pid>/ns/pid)
b4ec74
+	 * (0: not initialized)
b4ec74
+	 */
b4ec74
+	unsigned int pid_ns;
b4ec74
+
b4ec74
 	struct mmap_cache_t *mmap_cache;
b4ec74
 
b4ec74
 	/*
b4ec74
@@ -413,7 +420,11 @@
b4ec74
 # define RVAL_HEX	001	/* hex format */
b4ec74
 # define RVAL_OCTAL	002	/* octal format */
b4ec74
 # define RVAL_FD		010	/* file descriptor */
b4ec74
-# define RVAL_MASK	013	/* mask for these values */
b4ec74
+# define RVAL_TID	011	/* task ID */
b4ec74
+# define RVAL_SID	012	/* session ID */
b4ec74
+# define RVAL_TGID	013	/* thread group ID */
b4ec74
+# define RVAL_PGID	014	/* process group ID */
b4ec74
+# define RVAL_MASK	017	/* mask for these values */
b4ec74
 
b4ec74
 # define RVAL_STR	020	/* Print `auxstr' field after return val */
b4ec74
 # define RVAL_NONE	040	/* Print nothing */
b4ec74
@@ -428,6 +439,16 @@
b4ec74
 
b4ec74
 # define indirect_ipccall(tcp) (tcp_sysent(tcp)->sys_flags & TRACE_INDIRECT_SUBCALL)
b4ec74
 
b4ec74
+enum pid_type {
b4ec74
+	PT_TID,
b4ec74
+	PT_TGID,
b4ec74
+	PT_PGID,
b4ec74
+	PT_SID,
b4ec74
+
b4ec74
+	PT_COUNT,
b4ec74
+	PT_NONE = -1
b4ec74
+};
b4ec74
+
b4ec74
 enum sock_proto {
b4ec74
 	SOCK_PROTO_UNKNOWN,
b4ec74
 	SOCK_PROTO_UNIX,
b4ec74
@@ -469,6 +490,7 @@
b4ec74
 extern int Tflag_width;
b4ec74
 extern bool iflag;
b4ec74
 extern bool count_wallclock;
b4ec74
+extern unsigned int pidns_translation;
b4ec74
 /* are we filtering traces based on paths? */
b4ec74
 extern struct path_set {
b4ec74
 	const char **paths_selected;
b4ec74
@@ -984,6 +1006,29 @@
b4ec74
 extern kernel_ulong_t *
b4ec74
 fetch_indirect_syscall_args(struct tcb *, kernel_ulong_t addr, unsigned int n_args);
b4ec74
 
b4ec74
+extern void pidns_init(void);
b4ec74
+
b4ec74
+/**
b4ec74
+ * Returns the pid of the tracee as present in /proc of the tracer (can be
b4ec74
+ * different from tcp->pid if /proc and the tracer process are in different PID
b4ec74
+ * namespaces).
b4ec74
+ */
b4ec74
+extern int get_proc_pid(struct tcb *);
b4ec74
+
b4ec74
+/**
b4ec74
+ * Translates a pid from tracee's namespace to our namepace.
b4ec74
+ *
b4ec74
+ * @param tcp             The tcb of the tracee
b4ec74
+ *                        (NULL: from_id is in strace's namespace. Useful for
b4ec74
+ *                         getting the proc PID of from_id)
b4ec74
+ * @param from_id         The id to be translated
b4ec74
+ * @param type            The PID type of from_id
b4ec74
+ * @param proc_pid_ptr    If not NULL, writes the proc PID to this location
b4ec74
+ * @return                The translated id, or 0 if translation fails.
b4ec74
+ */
b4ec74
+extern int translate_pid(struct tcb *, int dest_id, enum pid_type type,
b4ec74
+		    int *proc_pid_ptr);
b4ec74
+
b4ec74
 extern void
b4ec74
 dumpiov_in_msghdr(struct tcb *, kernel_ulong_t addr, kernel_ulong_t data_size);
b4ec74
 
b4ec74
@@ -1059,6 +1104,15 @@
b4ec74
  * of the tracee the descriptor tcp).  This is a stub.
b4ec74
  */
b4ec74
 extern void printfd_pid_tracee_ns(struct tcb *tcp, pid_t pid, int fd);
b4ec74
+
b4ec74
+/** Prints a PID specified in the tracee's PID namespace */
b4ec74
+extern void printpid(struct tcb *, int pid, enum pid_type type);
b4ec74
+
b4ec74
+/**
b4ec74
+ * Prints pid as a TGID if positive, and PGID if negative
b4ec74
+ * (like the first argument of kill).
b4ec74
+ */
b4ec74
+extern void printpid_tgid_pgid(struct tcb *, int pid);
b4ec74
 extern void print_sockaddr(struct tcb *, const void *sa, int len);
b4ec74
 extern bool
b4ec74
 print_inet_addr(int af, const void *addr, unsigned int len, const char *var_name);
b4ec74
Index: strace-5.7/largefile_wrappers.h
b4ec74
===================================================================
b4ec74
--- strace-5.7.orig/largefile_wrappers.h	2020-09-09 15:50:13.473900511 +0200
b4ec74
+++ strace-5.7/largefile_wrappers.h	2020-09-09 15:50:18.017903762 +0200
b4ec74
@@ -29,6 +29,7 @@
b4ec74
 #  else
b4ec74
 #   define fcntl_fd fcntl
b4ec74
 #  endif
b4ec74
+#  define fstat_fd fstat64
b4ec74
 #  define strace_stat_t struct stat64
b4ec74
 #  define stat_file stat64
b4ec74
 #  define struct_dirent struct dirent64
b4ec74
@@ -39,6 +40,7 @@
b4ec74
 #  define open_file open
b4ec74
 #  define fopen_stream fopen
b4ec74
 #  define fcntl_fd fcntl
b4ec74
+#  define fstat_fd fstat
b4ec74
 #  define strace_stat_t struct stat
b4ec74
 #  define stat_file stat
b4ec74
 #  define struct_dirent struct dirent
b4ec74
Index: strace-5.7/pidns.c
b4ec74
===================================================================
b4ec74
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
b4ec74
+++ strace-5.7/pidns.c	2020-09-09 15:50:18.018903762 +0200
b4ec74
@@ -0,0 +1,608 @@
b4ec74
+/*
b4ec74
+ * Copyright (c) 2020 Ákos Uzonyi <uzonyi.akos@gmail.com>
b4ec74
+ * All rights reserved.
b4ec74
+ *
b4ec74
+ * SPDX-License-Identifier: LGPL-2.1-or-later
b4ec74
+ */
b4ec74
+
b4ec74
+#include "defs.h"
b4ec74
+
b4ec74
+
b4ec74
+#include <dirent.h>
b4ec74
+#include <fcntl.h>
b4ec74
+#include <stdint.h>
b4ec74
+#include <string.h>
b4ec74
+#include <unistd.h>
b4ec74
+
b4ec74
+#include <asm/unistd.h>
b4ec74
+
b4ec74
+#include <sys/ioctl.h>
b4ec74
+#include <sys/param.h>
b4ec74
+#include <sys/types.h>
b4ec74
+#include <sys/stat.h>
b4ec74
+
b4ec74
+#include "largefile_wrappers.h"
b4ec74
+#include "trie.h"
b4ec74
+#include "nsfs.h"
b4ec74
+#include "xmalloc.h"
b4ec74
+#include "xstring.h"
b4ec74
+
b4ec74
+/**
b4ec74
+ * Key:   PID NS ID
b4ec74
+ * Value: a btree:
b4ec74
+ *           Key:   a process PID in NS
b4ec74
+ *           Value: the process's PID as present in /proc
b4ec74
+ */
b4ec74
+static struct trie *ns_pid_to_proc_pid[PT_COUNT];
b4ec74
+
b4ec74
+/**
b4ec74
+ * Key:   Proc PID
b4ec74
+ * Value: struct proc_data
b4ec74
+ */
b4ec74
+static struct trie *proc_data_cache;
b4ec74
+
b4ec74
+static bool ns_get_parent_enotty = false;
b4ec74
+
b4ec74
+static const char tid_str[]  = "NSpid:\t";
b4ec74
+static const char tgid_str[] = "NStgid:\t";
b4ec74
+static const char pgid_str[] = "NSpgid:\t";
b4ec74
+static const char sid_str[]  = "NSsid:\t";
b4ec74
+
b4ec74
+static const struct {
b4ec74
+	const char *str;
b4ec74
+	size_t size;
b4ec74
+} id_strs[PT_COUNT] = {
b4ec74
+	[PT_TID] =  { tid_str,  sizeof(tid_str)  - 1 },
b4ec74
+	[PT_TGID] = { tgid_str, sizeof(tgid_str) - 1 },
b4ec74
+	[PT_PGID] = { pgid_str, sizeof(pgid_str) - 1 },
b4ec74
+	[PT_SID] =  { sid_str,  sizeof(sid_str)  - 1 },
b4ec74
+};
b4ec74
+
b4ec74
+
b4ec74
+/**
b4ec74
+ * Limit on PID NS hierarchy depth, imposed since Linux 3.7. NS traversal
b4ec74
+ * is not possible before Linux 4.9, so we consider this limit pretty universal.
b4ec74
+ */
b4ec74
+#define MAX_NS_DEPTH 32
b4ec74
+
b4ec74
+static const size_t ns_id_size = sizeof(unsigned int) * 8;
b4ec74
+static const uint8_t ptr_sz_lg = (sizeof(void *) == 8 ? 6 : 5);
b4ec74
+
b4ec74
+static int pid_max;
b4ec74
+static uint8_t pid_max_size, pid_max_size_lg;
b4ec74
+
b4ec74
+struct proc_data {
b4ec74
+	int proc_pid;
b4ec74
+	int ns_count;
b4ec74
+	unsigned int ns_hierarchy[MAX_NS_DEPTH];
b4ec74
+	int id_count[PT_COUNT];
b4ec74
+	int id_hierarchy[PT_COUNT][MAX_NS_DEPTH];
b4ec74
+};
b4ec74
+
b4ec74
+/**
b4ec74
+ * Helper function for creating a trie.
b4ec74
+ *
b4ec74
+ * For node_key_bits and data_block_key_bits 4 is used (so trie height is 32 / 4
b4ec74
+ * = 8, and node sizes are 8 byte * 2^4 = 128 bytes), which seems to be a good
b4ec74
+ * tradeoff between memory usage and lookup time. It should not be too large,
b4ec74
+ * since there can be large holes between PIDs, and it would be just a waste of
b4ec74
+ * memory having large nodes with lot of NULL pointers in them.
b4ec74
+ */
b4ec74
+static struct trie *
b4ec74
+create_trie_4(uint8_t key_size, uint8_t item_size_lg, uint64_t empty_value)
b4ec74
+{
b4ec74
+	struct trie *t = trie_create(key_size, item_size_lg, 4, 4, empty_value);
b4ec74
+	if (!t)
b4ec74
+		error_msg_and_die("creating trie failed");
b4ec74
+
b4ec74
+	return t;
b4ec74
+}
b4ec74
+
b4ec74
+void
b4ec74
+pidns_init(void)
b4ec74
+{
b4ec74
+	if (proc_data_cache)
b4ec74
+		return;
b4ec74
+
b4ec74
+	pid_max = INT_MAX;
b4ec74
+	if (read_int_from_file("/proc/sys/kernel/pid_max", &pid_max) < 0)
b4ec74
+		debug_func_perror_msg("reading /proc/sys/kernel/pid_max");
b4ec74
+	pid_max_size = ilog2_32(pid_max - 1) + 1;
b4ec74
+	pid_max_size_lg = ilog2_32(pid_max_size - 1) + 1;
b4ec74
+
b4ec74
+	for (int i = 0; i < PT_COUNT; i++)
b4ec74
+		ns_pid_to_proc_pid[i] = create_trie_4(ns_id_size, ptr_sz_lg, 0);
b4ec74
+
b4ec74
+	proc_data_cache = create_trie_4(pid_max_size, ptr_sz_lg, 0);
b4ec74
+}
b4ec74
+
b4ec74
+static void
b4ec74
+put_proc_pid(unsigned int ns, int ns_pid, enum pid_type type, int proc_pid)
b4ec74
+{
b4ec74
+	struct trie *b = (struct trie *) (uintptr_t) trie_get(ns_pid_to_proc_pid[type], ns);
b4ec74
+	if (!b) {
b4ec74
+		b = create_trie_4(pid_max_size, pid_max_size_lg, 0);
b4ec74
+		trie_set(ns_pid_to_proc_pid[type], ns, (uint64_t) (uintptr_t) b);
b4ec74
+	}
b4ec74
+	trie_set(b, ns_pid, proc_pid);
b4ec74
+}
b4ec74
+
b4ec74
+static int
b4ec74
+get_cached_proc_pid(unsigned int ns, int ns_pid, enum pid_type type)
b4ec74
+{
b4ec74
+	struct trie *b = (struct trie *) (uintptr_t)
b4ec74
+		trie_get(ns_pid_to_proc_pid[type], ns);
b4ec74
+	if (!b)
b4ec74
+		return 0;
b4ec74
+
b4ec74
+	return trie_get(b, ns_pid);
b4ec74
+}
b4ec74
+
b4ec74
+/**
b4ec74
+ * Helper function, converts pid to string, or to "self" for pid == 0.
b4ec74
+ * Uses static buffer for operation.
b4ec74
+ */
b4ec74
+static const char *
b4ec74
+pid_to_str(pid_t pid)
b4ec74
+{
b4ec74
+	if (!pid)
b4ec74
+		return "self";
b4ec74
+
b4ec74
+	static char buf[sizeof("-2147483648")];
b4ec74
+	xsprintf(buf, "%d", pid);
b4ec74
+	return buf;
b4ec74
+}
b4ec74
+
b4ec74
+/**
b4ec74
+ * Returns a list of PID NS IDs for the specified PID.
b4ec74
+ *
b4ec74
+ * @param proc_pid PID (as present in /proc) to get information for.
b4ec74
+ * @param ns_buf   Pointer to buffer that is able to contain at least
b4ec74
+ *                 ns_buf_size items.
b4ec74
+ * @return         Amount of NS in list. 0 indicates error.
b4ec74
+ */
b4ec74
+static size_t
b4ec74
+get_ns_hierarchy(int proc_pid, unsigned int *ns_buf, size_t ns_buf_size)
b4ec74
+{
b4ec74
+	char path[PATH_MAX + 1];
b4ec74
+	xsprintf(path, "/proc/%s/ns/pid", pid_to_str(proc_pid));
b4ec74
+
b4ec74
+	int fd = open_file(path, O_RDONLY);
b4ec74
+	if (fd < 0)
b4ec74
+		return 0;
b4ec74
+
b4ec74
+	size_t n = 0;
b4ec74
+	while (n < ns_buf_size) {
b4ec74
+		strace_stat_t st;
b4ec74
+		if (fstat_fd(fd, &st))
b4ec74
+			break;
b4ec74
+
b4ec74
+		ns_buf[n++] = st.st_ino;
b4ec74
+		if (n >= ns_buf_size)
b4ec74
+			break;
b4ec74
+
b4ec74
+		if (ns_get_parent_enotty)
b4ec74
+			break;
b4ec74
+
b4ec74
+		int parent_fd = ioctl(fd, NS_GET_PARENT);
b4ec74
+		if (parent_fd < 0) {
b4ec74
+			switch (errno) {
b4ec74
+			case EPERM:
b4ec74
+				break;
b4ec74
+
b4ec74
+			case ENOTTY:
b4ec74
+				ns_get_parent_enotty = true;
b4ec74
+				error_msg("NS_* ioctl commands are not "
b4ec74
+					  "supported by the kernel");
b4ec74
+				break;
b4ec74
+
b4ec74
+			default:
b4ec74
+				perror_func_msg("ioctl(NS_GET_PARENT)");
b4ec74
+				break;
b4ec74
+			}
b4ec74
+
b4ec74
+			break;
b4ec74
+		}
b4ec74
+
b4ec74
+		close(fd);
b4ec74
+		fd = parent_fd;
b4ec74
+	}
b4ec74
+
b4ec74
+	close(fd);
b4ec74
+
b4ec74
+	return n;
b4ec74
+}
b4ec74
+
b4ec74
+/**
b4ec74
+ * Get list of IDs present in NS* proc status record. IDs are placed as they are
b4ec74
+ * stored in /proc (from top to bottom of NS hierarchy).
b4ec74
+ *
b4ec74
+ * @param proc_pid    PID (as present in /proc) to get information for.
b4ec74
+ * @param id_buf      Pointer to buffer that is able to contain at least
b4ec74
+ *                    MAX_NS_DEPTH items. Can be NULL.
b4ec74
+ * @param type        Type of ID requested.
b4ec74
+ * @return            Number of items stored in id_list. 0 indicates error.
b4ec74
+ */
b4ec74
+static size_t
b4ec74
+get_id_list(int proc_pid, int *id_buf, enum pid_type type)
b4ec74
+{
b4ec74
+	const char *ns_str = id_strs[type].str;
b4ec74
+	size_t ns_str_size = id_strs[type].size;
b4ec74
+
b4ec74
+	size_t n = 0;
b4ec74
+
b4ec74
+	char status_path[PATH_MAX + 1];
b4ec74
+	xsprintf(status_path, "/proc/%s/status", pid_to_str(proc_pid));
b4ec74
+	FILE *f = fopen_stream(status_path, "r");
b4ec74
+	if (!f)
b4ec74
+		return 0;
b4ec74
+
b4ec74
+	char *line = NULL;
b4ec74
+	size_t linesize = 0;
b4ec74
+	char *p = NULL;
b4ec74
+
b4ec74
+	while (getline(&line, &linesize, f) > 0) {
b4ec74
+		if (strncmp(line, ns_str, ns_str_size) == 0) {
b4ec74
+			p = line + ns_str_size;
b4ec74
+			break;
b4ec74
+		}
b4ec74
+	}
b4ec74
+
b4ec74
+	while (p) {
b4ec74
+		errno = 0;
b4ec74
+		long id = strtol(p, NULL, 10);
b4ec74
+
b4ec74
+		if (id < 0 || id > INT_MAX || errno) {
b4ec74
+			perror_func_msg("converting pid (%ld) to int", id);
b4ec74
+			break;
b4ec74
+		}
b4ec74
+
b4ec74
+		if (id_buf)
b4ec74
+			id_buf[n] = (int) id;
b4ec74
+
b4ec74
+		n++;
b4ec74
+		strsep(&p, "\t");
b4ec74
+	}
b4ec74
+
b4ec74
+	free(line);
b4ec74
+	fclose(f);
b4ec74
+
b4ec74
+	return n;
b4ec74
+}
b4ec74
+
b4ec74
+/**
b4ec74
+ * Returns whether the /proc filesystem's PID namespace is the same as strace's.
b4ec74
+ */
b4ec74
+static bool
b4ec74
+is_proc_ours(void)
b4ec74
+{
b4ec74
+	static int cached_val = -1;
b4ec74
+
b4ec74
+	if (cached_val < 0)
b4ec74
+		cached_val = get_id_list(0, NULL, PT_TID) <= 1;
b4ec74
+
b4ec74
+	return cached_val;
b4ec74
+}
b4ec74
+
b4ec74
+/**
b4ec74
+ * Returns the PID namespace of the tracee
b4ec74
+ */
b4ec74
+static unsigned int
b4ec74
+get_ns(struct tcb *tcp)
b4ec74
+{
b4ec74
+	if (!tcp->pid_ns) {
b4ec74
+		int proc_pid = 0;
b4ec74
+		translate_pid(NULL, tcp->pid, PT_TID, &proc_pid);
b4ec74
+
b4ec74
+		if (proc_pid)
b4ec74
+			get_ns_hierarchy(proc_pid, &tcp->pid_ns, 1);
b4ec74
+	}
b4ec74
+
b4ec74
+	return tcp->pid_ns;
b4ec74
+}
b4ec74
+
b4ec74
+/**
b4ec74
+ * Returns the PID namespace of strace
b4ec74
+ */
b4ec74
+static unsigned int
b4ec74
+get_our_ns(void)
b4ec74
+{
b4ec74
+	static unsigned int our_ns = 0;
b4ec74
+	static bool our_ns_initialised = false;
b4ec74
+
b4ec74
+	if (!our_ns_initialised) {
b4ec74
+		get_ns_hierarchy(0, &our_ns, 1);
b4ec74
+		our_ns_initialised = true;
b4ec74
+	}
b4ec74
+
b4ec74
+	return our_ns;
b4ec74
+}
b4ec74
+
b4ec74
+/**
b4ec74
+ * Returns the cached proc_data struct associated with proc_pid.
b4ec74
+ * If none found, allocates a new proc_data.
b4ec74
+ */
b4ec74
+static struct proc_data *
b4ec74
+get_or_create_proc_data(int proc_pid)
b4ec74
+{
b4ec74
+	struct proc_data *pd = (struct proc_data *) (uintptr_t)
b4ec74
+		trie_get(proc_data_cache, proc_pid);
b4ec74
+
b4ec74
+	if (!pd) {
b4ec74
+		pd = calloc(1, sizeof(*pd));
b4ec74
+		if (!pd)
b4ec74
+			return NULL;
b4ec74
+
b4ec74
+		pd->proc_pid = proc_pid;
b4ec74
+		trie_set(proc_data_cache, proc_pid, (uint64_t) (uintptr_t) pd);
b4ec74
+	}
b4ec74
+
b4ec74
+	return pd;
b4ec74
+}
b4ec74
+
b4ec74
+/**
b4ec74
+ * Updates the proc_data from /proc
b4ec74
+ * If the process does not exists, returns false, and frees the proc_data
b4ec74
+ */
b4ec74
+static bool
b4ec74
+update_proc_data(struct proc_data *pd, enum pid_type type)
b4ec74
+{
b4ec74
+	pd->ns_count = get_ns_hierarchy(pd->proc_pid,
b4ec74
+		pd->ns_hierarchy, MAX_NS_DEPTH);
b4ec74
+	if (!pd->ns_count)
b4ec74
+		goto fail;
b4ec74
+
b4ec74
+	pd->id_count[type] = get_id_list(pd->proc_pid,
b4ec74
+		pd->id_hierarchy[type], type);
b4ec74
+	if (!pd->id_count[type])
b4ec74
+		goto fail;
b4ec74
+
b4ec74
+	return true;
b4ec74
+
b4ec74
+fail:
b4ec74
+	trie_set(proc_data_cache, pd->proc_pid, (uint64_t) (uintptr_t) NULL);
b4ec74
+	free(pd);
b4ec74
+	return false;
b4ec74
+}
b4ec74
+
b4ec74
+/**
b4ec74
+ * Paramters for id translation
b4ec74
+ */
b4ec74
+struct translate_id_params {
b4ec74
+	/* The result (output) */
b4ec74
+	int result_id;
b4ec74
+	/* The proc data of the process (output) */
b4ec74
+	struct proc_data *pd;
b4ec74
+
b4ec74
+	/* The namespace to be translated from */
b4ec74
+	unsigned int from_ns;
b4ec74
+	/* The id to be translated */
b4ec74
+	int from_id;
b4ec74
+	/* The type of the id */
b4ec74
+	enum pid_type type;
b4ec74
+};
b4ec74
+
b4ec74
+/**
b4ec74
+ * Translates an id to our namespace, given the proc_pid of the process,
b4ec74
+ * by reading files in /proc.
b4ec74
+ *
b4ec74
+ * @param tip      The parameters
b4ec74
+ * @param proc_pid The proc pid of the process.
b4ec74
+ *                 If 0, use the cached values in tip->pd.
b4ec74
+ */
b4ec74
+static void
b4ec74
+translate_id_proc_pid(struct translate_id_params *tip, int proc_pid)
b4ec74
+{
b4ec74
+	struct proc_data *pd = proc_pid ?
b4ec74
+		get_or_create_proc_data(proc_pid) :
b4ec74
+		tip->pd;
b4ec74
+
b4ec74
+	tip->result_id = 0;
b4ec74
+	tip->pd = NULL;
b4ec74
+
b4ec74
+	if (!pd)
b4ec74
+		return;
b4ec74
+
b4ec74
+	if (proc_pid && !update_proc_data(pd, tip->type))
b4ec74
+		return;
b4ec74
+
b4ec74
+	if (!pd->ns_count || pd->id_count[tip->type] < pd->ns_count)
b4ec74
+		return;
b4ec74
+
b4ec74
+	int *id_hierarchy = pd->id_hierarchy[tip->type];
b4ec74
+	int id_count = pd->id_count[tip->type];
b4ec74
+
b4ec74
+	for (int i = 0; i < pd->ns_count; i++) {
b4ec74
+		unsigned int ns = pd->ns_hierarchy[i];
b4ec74
+		int ns_id = id_hierarchy[id_count - i - 1];
b4ec74
+		int our_id = id_hierarchy[id_count - pd->ns_count];
b4ec74
+
b4ec74
+		if (ns != tip->from_ns)
b4ec74
+			continue;
b4ec74
+
b4ec74
+		if (ns_id != tip->from_id)
b4ec74
+			return;
b4ec74
+
b4ec74
+		tip->result_id = our_id;
b4ec74
+		tip->pd = pd;
b4ec74
+		return;
b4ec74
+	}
b4ec74
+}
b4ec74
+
b4ec74
+/**
b4ec74
+ * Translates an id to our namespace by reading all proc entries in a directory.
b4ec74
+ * The directory is either /proc or /proc/<pid>/task.
b4ec74
+ *
b4ec74
+ *
b4ec74
+ * @param tip            The parameters
b4ec74
+ * @param path           The path of the directory to be read.
b4ec74
+ * @param read_task_dir  Whether recurse to "task" subdirectory.
b4ec74
+ */
b4ec74
+static void
b4ec74
+translate_id_dir(struct translate_id_params *tip, const char *path,
b4ec74
+                 bool read_task_dir)
b4ec74
+{
b4ec74
+	DIR *dir = opendir(path);
b4ec74
+	if (!dir) {
b4ec74
+		debug_func_perror_msg("opening dir: %s", path);
b4ec74
+		return;
b4ec74
+	}
b4ec74
+
b4ec74
+	while (!tip->result_id) {
b4ec74
+		errno = 0;
b4ec74
+		struct_dirent *entry = read_dir(dir);
b4ec74
+		if (!entry) {
b4ec74
+			if (errno)
b4ec74
+				perror_func_msg("readdir");
b4ec74
+
b4ec74
+			break;
b4ec74
+		}
b4ec74
+
b4ec74
+		if (entry->d_type != DT_DIR)
b4ec74
+			continue;
b4ec74
+
b4ec74
+		errno = 0;
b4ec74
+		long proc_pid = strtol(entry->d_name, NULL, 10);
b4ec74
+		if (proc_pid < 1 || proc_pid > INT_MAX || errno)
b4ec74
+			continue;
b4ec74
+
b4ec74
+		if (read_task_dir) {
b4ec74
+			char task_dir_path[PATH_MAX + 1];
b4ec74
+			xsprintf(task_dir_path, "/proc/%ld/task", proc_pid);
b4ec74
+			translate_id_dir(tip, task_dir_path, false);
b4ec74
+		}
b4ec74
+
b4ec74
+		if (tip->result_id)
b4ec74
+			break;
b4ec74
+
b4ec74
+		translate_id_proc_pid(tip, proc_pid);
b4ec74
+	}
b4ec74
+
b4ec74
+	closedir(dir);
b4ec74
+}
b4ec74
+
b4ec74
+/**
b4ec74
+ * Iterator function of the proc_data_cache for id translation.
b4ec74
+ * If the cache contains the id we are looking for, reads the corresponding
b4ec74
+ * directory in /proc, and if cache is valid, saves the result.
b4ec74
+ */
b4ec74
+static void
b4ec74
+proc_data_cache_iterator_fn(void* fn_data, uint64_t key, uint64_t val)
b4ec74
+{
b4ec74
+	struct translate_id_params *tip = (struct translate_id_params *)fn_data;
b4ec74
+	struct proc_data *pd = (struct proc_data *) (uintptr_t) val;
b4ec74
+
b4ec74
+	if (!pd)
b4ec74
+		return;
b4ec74
+
b4ec74
+	/* Result already found in an earlier iteration */
b4ec74
+	if (tip->result_id)
b4ec74
+		return;
b4ec74
+
b4ec74
+	/* Translate from cache */
b4ec74
+	tip->pd = pd;
b4ec74
+	translate_id_proc_pid(tip, 0);
b4ec74
+	if (!tip->result_id)
b4ec74
+		return;
b4ec74
+
b4ec74
+	/* Now translate from actual data in /proc, to check cache validity */
b4ec74
+	translate_id_proc_pid(tip, pd->proc_pid);
b4ec74
+}
b4ec74
+
b4ec74
+int
b4ec74
+translate_pid(struct tcb *tcp, int from_id, enum pid_type type,
b4ec74
+              int *proc_pid_ptr)
b4ec74
+{
b4ec74
+	if (from_id <= 0 || type < 0 || type >= PT_COUNT)
b4ec74
+		return 0;
b4ec74
+
b4ec74
+	/* If translation is trivial */
b4ec74
+	if ((!tcp || get_ns(tcp) == get_our_ns()) &&
b4ec74
+	    (!proc_pid_ptr || is_proc_ours())) {
b4ec74
+		if (proc_pid_ptr)
b4ec74
+			*proc_pid_ptr = from_id;
b4ec74
+
b4ec74
+		return from_id;
b4ec74
+	}
b4ec74
+
b4ec74
+	struct translate_id_params tip = {
b4ec74
+		.result_id = 0,
b4ec74
+		.pd = NULL,
b4ec74
+		.from_ns = tcp ? get_ns(tcp) : get_our_ns(),
b4ec74
+		.from_id = from_id,
b4ec74
+		.type = type,
b4ec74
+	};
b4ec74
+
b4ec74
+	if (!tip.from_ns)
b4ec74
+		return 0;
b4ec74
+
b4ec74
+	if (ns_get_parent_enotty)
b4ec74
+		return 0;
b4ec74
+
b4ec74
+	/* Look for a cached proc_pid for this (from_ns, from_id) pair */
b4ec74
+	int cached_proc_pid = get_cached_proc_pid(tip.from_ns, tip.from_id,
b4ec74
+		tip.type);
b4ec74
+	if (cached_proc_pid) {
b4ec74
+		translate_id_proc_pid(&tip, cached_proc_pid);
b4ec74
+		if (tip.result_id)
b4ec74
+			goto exit;
b4ec74
+	}
b4ec74
+
b4ec74
+	/* Iterate through the cache, find potential proc_data */
b4ec74
+	trie_iterate_keys(proc_data_cache, 0, pid_max - 1,
b4ec74
+		proc_data_cache_iterator_fn, &tip;;
b4ec74
+	/* (proc_data_cache_iterator_fn takes care about updating proc_data) */
b4ec74
+	if (tip.result_id)
b4ec74
+		goto exit;
b4ec74
+
b4ec74
+	/* No cache helped, read all entries in /proc */
b4ec74
+	translate_id_dir(&tip, "/proc", true);
b4ec74
+
b4ec74
+exit:
b4ec74
+	if (tip.pd) {
b4ec74
+		if (tip.pd->proc_pid)
b4ec74
+			put_proc_pid(tip.from_ns, tip.from_id, tip.type,
b4ec74
+				tip.pd->proc_pid);
b4ec74
+
b4ec74
+		if (proc_pid_ptr)
b4ec74
+			*proc_pid_ptr = tip.pd->proc_pid;
b4ec74
+	}
b4ec74
+
b4ec74
+	return tip.result_id;
b4ec74
+}
b4ec74
+
b4ec74
+int
b4ec74
+get_proc_pid(struct tcb *tcp)
b4ec74
+{
b4ec74
+	int proc_pid = 0;
b4ec74
+	translate_pid(NULL, tcp->pid, PT_TID, &proc_pid);
b4ec74
+	return proc_pid;
b4ec74
+}
b4ec74
+
b4ec74
+static void
b4ec74
+printpid_translation(struct tcb *tcp, int pid, enum pid_type type)
b4ec74
+{
b4ec74
+	if (!pidns_translation)
b4ec74
+		return;
b4ec74
+
b4ec74
+	int strace_pid = translate_pid(tcp, pid, type, NULL);
b4ec74
+	if (strace_pid && strace_pid != pid)
b4ec74
+		tprintf_comment("%d in strace's PID NS", strace_pid);
b4ec74
+}
b4ec74
+
b4ec74
+void
b4ec74
+printpid(struct tcb *tcp, int pid, enum pid_type type)
b4ec74
+{
b4ec74
+	tprintf("%d", pid);
b4ec74
+	printpid_translation(tcp, pid, type);
b4ec74
+}
b4ec74
+
b4ec74
+void
b4ec74
+printpid_tgid_pgid(struct tcb *tcp, int pid)
b4ec74
+{
b4ec74
+	tprintf("%d", pid);
b4ec74
+	if (pid > 0)
b4ec74
+		printpid_translation(tcp,  pid, PT_TGID);
b4ec74
+	else if (pid < -1)
b4ec74
+		printpid_translation(tcp, -pid, PT_PGID);
b4ec74
+}
b4ec74
Index: strace-5.7/strace.1.in
b4ec74
===================================================================
b4ec74
--- strace-5.7.orig/strace.1.in	2020-09-09 15:50:13.475900513 +0200
b4ec74
+++ strace-5.7/strace.1.in	2020-09-09 15:50:18.018903762 +0200
b4ec74
@@ -1075,6 +1075,10 @@
b4ec74
 protocol-specific information associated with socket file descriptors,
b4ec74
 block/character device number associated with device file descriptors,
b4ec74
 and PIDs asociated with pidfd file descriptors.
b4ec74
+.TP
b4ec74
+.B \-\-pidns\-translation
b4ec74
+If strace and tracee are in different PID namespaces, print PIDs in
b4ec74
+strace's namespace, too.
b4ec74
 .SS Statistics
b4ec74
 .TP 12
b4ec74
 .B \-c
b4ec74
Index: strace-5.7/strace.c
b4ec74
===================================================================
b4ec74
--- strace-5.7.orig/strace.c	2020-09-09 15:50:13.476900514 +0200
b4ec74
+++ strace-5.7/strace.c	2020-09-09 15:52:08.646982890 +0200
b4ec74
@@ -133,6 +133,8 @@
b4ec74
 static int post_attach_sigstop = TCB_IGNORE_ONE_SIGSTOP;
b4ec74
 #define use_seize (post_attach_sigstop == 0)
b4ec74
 
b4ec74
+unsigned int pidns_translation;
b4ec74
+
b4ec74
 static bool detach_on_execve;
b4ec74
 
b4ec74
 static int exit_code;
b4ec74
@@ -1998,6 +2000,8 @@
b4ec74
 
b4ec74
 	os_release = get_os_release();
b4ec74
 
b4ec74
+	pidns_init();
b4ec74
+
b4ec74
 	shared_log = stderr;
b4ec74
 	set_sortby(DEFAULT_SORTBY);
b4ec74
 	set_personality(DEFAULT_PERSONALITY);
b4ec74
@@ -2022,6 +2026,7 @@
b4ec74
 		GETOPT_FOLLOWFORKS,
b4ec74
 		GETOPT_OUTPUT_SEPARATELY,
b4ec74
 		GETOPT_TS,
b4ec74
+		GETOPT_PIDNS_TRANSLATION,
b4ec74
 
b4ec74
 		GETOPT_QUAL_TRACE,
b4ec74
 		GETOPT_QUAL_ABBREV,
b4ec74
@@ -2072,6 +2077,7 @@
b4ec74
 		{ "summary-wall-clock", no_argument,	   0, 'w' },
b4ec74
 		{ "strings-in-hex",	optional_argument, 0, GETOPT_HEX_STR },
b4ec74
 		{ "const-print-style",	required_argument, 0, 'X' },
b4ec74
+		{ "pidns-translation",	no_argument      , 0, GETOPT_PIDNS_TRANSLATION },
b4ec74
 		{ "successful-only",	no_argument,	   0, 'z' },
b4ec74
 		{ "failed-only",	no_argument,	   0, 'Z' },
b4ec74
 		{ "failing-only",	no_argument,	   0, 'Z' },
b4ec74
@@ -2285,6 +2291,9 @@
b4ec74
 		case 'y':
b4ec74
 			yflag_short++;
b4ec74
 			break;
b4ec74
+		case GETOPT_PIDNS_TRANSLATION:
b4ec74
+			pidns_translation++;
b4ec74
+			break;
b4ec74
 		case 'z':
b4ec74
 			clear_number_set_array(status_set, 1);
b4ec74
 			add_number_to_set(STATUS_SUCCESSFUL, status_set);
b4ec74
Index: strace-5.7/syscall.c
b4ec74
===================================================================
b4ec74
--- strace-5.7.orig/syscall.c	2020-09-09 15:50:13.477900514 +0200
b4ec74
+++ strace-5.7/syscall.c	2020-09-09 15:50:18.019903763 +0200
b4ec74
@@ -930,6 +930,21 @@
b4ec74
 					tprintf("= %" PRI_kld, tcp->u_rval);
b4ec74
 				}
b4ec74
 				break;
b4ec74
+			case RVAL_TID:
b4ec74
+			case RVAL_SID:
b4ec74
+			case RVAL_TGID:
b4ec74
+			case RVAL_PGID: {
b4ec74
+				#define _(_t) [RVAL_##_t - RVAL_TID] = PT_##_t
b4ec74
+				static const enum pid_type types[] = {
b4ec74
+					_(TID), _(SID), _(TGID), _(PGID),
b4ec74
+				};
b4ec74
+				#undef _
b4ec74
+
b4ec74
+				tprints("= ");
b4ec74
+				printpid(tcp, tcp->u_rval,
b4ec74
+					 types[(sys_res & RVAL_MASK) - RVAL_TID]);
b4ec74
+				break;
b4ec74
+			}
b4ec74
 			default:
b4ec74
 				error_msg("invalid rval format");
b4ec74
 				break;
b4ec74
Index: strace-5.7/trie.c
b4ec74
===================================================================
b4ec74
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
b4ec74
+++ strace-5.7/trie.c	2020-09-09 15:50:18.019903763 +0200
b4ec74
@@ -0,0 +1,290 @@
b4ec74
+/*
b4ec74
+ * Simple trie implementation for key-value mapping storage
b4ec74
+ *
b4ec74
+ * Copyright (c) 2020 Ákos Uzonyi <uzonyi.akos@gmail.com>
b4ec74
+ * All rights reserved.
b4ec74
+ *
b4ec74
+ * SPDX-License-Identifier: LGPL-2.1-or-later
b4ec74
+ */
b4ec74
+
b4ec74
+#ifdef HAVE_CONFIG_H
b4ec74
+# include "config.h"
b4ec74
+#endif
b4ec74
+
b4ec74
+#include <stdlib.h>
b4ec74
+#include <stdio.h>
b4ec74
+
b4ec74
+#include "trie.h"
b4ec74
+#include "xmalloc.h"
b4ec74
+
b4ec74
+static const uint8_t ptr_sz_lg = (sizeof(void *) == 8 ? 6 : 5);
b4ec74
+
b4ec74
+/**
b4ec74
+ * Returns lg2 of node size in bits for the specific level of the trie.
b4ec74
+ */
b4ec74
+static uint8_t
b4ec74
+trie_get_node_size(struct trie *t, uint8_t depth)
b4ec74
+{
b4ec74
+	/* Last level contains data and we allow it having a different size */
b4ec74
+	if (depth == t->max_depth)
b4ec74
+		return t->data_block_key_bits + t->item_size_lg;
b4ec74
+	/* Last level of the tree can be smaller */
b4ec74
+	if (depth == t->max_depth - 1)
b4ec74
+		return (t->key_size - t->data_block_key_bits - 1) %
b4ec74
+		t->node_key_bits + 1 + ptr_sz_lg;
b4ec74
+
b4ec74
+	return t->node_key_bits + ptr_sz_lg;
b4ec74
+}
b4ec74
+
b4ec74
+/**
b4ec74
+ * Provides starting offset of bits in key corresponding to the node index
b4ec74
+ * at the specific level.
b4ec74
+ */
b4ec74
+static uint8_t
b4ec74
+trie_get_node_bit_offs(struct trie *t, uint8_t depth)
b4ec74
+{
b4ec74
+	uint8_t offs;
b4ec74
+
b4ec74
+	if (depth == t->max_depth)
b4ec74
+		return 0;
b4ec74
+
b4ec74
+	offs = t->data_block_key_bits;
b4ec74
+
b4ec74
+	if (depth == t->max_depth - 1)
b4ec74
+		return offs;
b4ec74
+
b4ec74
+	/* data_block_size + remainder */
b4ec74
+	offs += trie_get_node_size(t, t->max_depth - 1) - ptr_sz_lg;
b4ec74
+	offs += (t->max_depth - depth - 2) * t->node_key_bits;
b4ec74
+
b4ec74
+	return offs;
b4ec74
+}
b4ec74
+
b4ec74
+struct trie *
b4ec74
+trie_create(uint8_t key_size, uint8_t item_size_lg, uint8_t node_key_bits,
b4ec74
+            uint8_t data_block_key_bits, uint64_t empty_value)
b4ec74
+{
b4ec74
+	if (item_size_lg > 6)
b4ec74
+		return NULL;
b4ec74
+	if (key_size > 64)
b4ec74
+		return NULL;
b4ec74
+	if (node_key_bits < 1)
b4ec74
+		return NULL;
b4ec74
+	if (data_block_key_bits < 1 || data_block_key_bits > key_size)
b4ec74
+		return NULL;
b4ec74
+
b4ec74
+	struct trie *t = malloc(sizeof(*t));
b4ec74
+	if (!t)
b4ec74
+		return NULL;
b4ec74
+
b4ec74
+	t->empty_value = empty_value;
b4ec74
+	t->data = NULL;
b4ec74
+	t->item_size_lg = item_size_lg;
b4ec74
+	t->node_key_bits = node_key_bits;
b4ec74
+	t->data_block_key_bits = data_block_key_bits;
b4ec74
+	t->key_size = key_size;
b4ec74
+	t->max_depth = (key_size - data_block_key_bits + node_key_bits - 1)
b4ec74
+		/ t->node_key_bits;
b4ec74
+
b4ec74
+	if (item_size_lg != 6)
b4ec74
+		t->empty_value &= (((uint64_t) 1 << (1 << t->item_size_lg)) - 1);
b4ec74
+
b4ec74
+	return t;
b4ec74
+}
b4ec74
+
b4ec74
+static void *
b4ec74
+trie_create_data_block(struct trie *t)
b4ec74
+{
b4ec74
+	uint64_t fill_value = t->empty_value;
b4ec74
+	for (int i = 1; i < 1 << (6 - t->item_size_lg); i++) {
b4ec74
+		fill_value <<= (1 << t->item_size_lg);
b4ec74
+		fill_value |= t->empty_value;
b4ec74
+	}
b4ec74
+
b4ec74
+	uint8_t sz = t->data_block_key_bits + t->item_size_lg;
b4ec74
+	if (sz < 6)
b4ec74
+		sz = 6;
b4ec74
+
b4ec74
+	size_t count = 1 << (sz - 6);
b4ec74
+	uint64_t *data_block = xcalloc(count, 8);
b4ec74
+
b4ec74
+	for (size_t i = 0; i < count; i++)
b4ec74
+		data_block[i] = fill_value;
b4ec74
+
b4ec74
+	return data_block;
b4ec74
+}
b4ec74
+
b4ec74
+static uint64_t *
b4ec74
+trie_get_node(struct trie *t, uint64_t key, bool auto_create)
b4ec74
+{
b4ec74
+	void **cur_node = &(t->data);
b4ec74
+
b4ec74
+	if (t->key_size < 64 && key > (uint64_t) 1 << t->key_size)
b4ec74
+		return NULL;
b4ec74
+
b4ec74
+	for (uint8_t cur_depth = 0; cur_depth <= t->max_depth; cur_depth++) {
b4ec74
+		uint8_t offs = trie_get_node_bit_offs(t, cur_depth);
b4ec74
+		uint8_t sz = trie_get_node_size(t, cur_depth);
b4ec74
+
b4ec74
+		if (!*cur_node) {
b4ec74
+			if (!auto_create)
b4ec74
+				return NULL;
b4ec74
+
b4ec74
+			if (cur_depth == t->max_depth)
b4ec74
+				*cur_node = trie_create_data_block(t);
b4ec74
+			else
b4ec74
+				*cur_node = xcalloc(1 << sz, 1);
b4ec74
+		}
b4ec74
+
b4ec74
+		if (cur_depth == t->max_depth)
b4ec74
+			break;
b4ec74
+
b4ec74
+		size_t pos = (key >> offs) & ((1 << (sz - ptr_sz_lg)) - 1);
b4ec74
+		cur_node = (((void **) (*cur_node)) + pos);
b4ec74
+	}
b4ec74
+
b4ec74
+	return (uint64_t *) (*cur_node);
b4ec74
+}
b4ec74
+
b4ec74
+static void
b4ec74
+trie_data_block_calc_pos(struct trie *t, uint64_t key,
b4ec74
+                         uint64_t *pos, uint64_t *mask, uint64_t *offs)
b4ec74
+{
b4ec74
+	uint64_t key_mask;
b4ec74
+
b4ec74
+	key_mask = (1 << t->data_block_key_bits) - 1;
b4ec74
+	*pos = (key & key_mask) >> (6 - t->item_size_lg);
b4ec74
+
b4ec74
+	if (t->item_size_lg == 6) {
b4ec74
+		*offs = 0;
b4ec74
+		*mask = -1;
b4ec74
+		return;
b4ec74
+	}
b4ec74
+
b4ec74
+	key_mask = (1 << (6 - t->item_size_lg)) - 1;
b4ec74
+	*offs = (key & key_mask) * (1 << t->item_size_lg);
b4ec74
+
b4ec74
+	*mask = (((uint64_t) 1 << (1 << t->item_size_lg)) - 1) << *offs;
b4ec74
+}
b4ec74
+
b4ec74
+bool
b4ec74
+trie_set(struct trie *t, uint64_t key, uint64_t val)
b4ec74
+{
b4ec74
+	uint64_t *data = trie_get_node(t, key, true);
b4ec74
+	if (!data)
b4ec74
+		return false;
b4ec74
+
b4ec74
+	uint64_t pos, mask, offs;
b4ec74
+	trie_data_block_calc_pos(t, key, &pos, &mask, &offs);
b4ec74
+
b4ec74
+	data[pos] &= ~mask;
b4ec74
+	data[pos] |= (val << offs) & mask;
b4ec74
+
b4ec74
+	return true;
b4ec74
+}
b4ec74
+
b4ec74
+static uint64_t
b4ec74
+trie_data_block_get(struct trie *t, uint64_t *data, uint64_t key)
b4ec74
+{
b4ec74
+	if (!data)
b4ec74
+		return t->empty_value;
b4ec74
+
b4ec74
+	uint64_t pos, mask, offs;
b4ec74
+	trie_data_block_calc_pos(t, key, &pos, &mask, &offs);
b4ec74
+
b4ec74
+	return (data[pos] & mask) >> offs;
b4ec74
+}
b4ec74
+
b4ec74
+uint64_t
b4ec74
+trie_get(struct trie *b, uint64_t key)
b4ec74
+{
b4ec74
+	return trie_data_block_get(b, trie_get_node(b, key, false), key);
b4ec74
+}
b4ec74
+
b4ec74
+static uint64_t
b4ec74
+trie_iterate_keys_node(struct trie *t,
b4ec74
+                       trie_iterate_fn fn, void *fn_data,
b4ec74
+                       void *node, uint64_t start, uint64_t end,
b4ec74
+                       uint8_t depth)
b4ec74
+{
b4ec74
+	if (start > end || !node)
b4ec74
+		return 0;
b4ec74
+
b4ec74
+	if (t->key_size < 64) {
b4ec74
+		uint64_t key_max = ((uint64_t) 1 << t->key_size) - 1;
b4ec74
+		if (end > key_max)
b4ec74
+			end = key_max;
b4ec74
+	}
b4ec74
+
b4ec74
+	if (depth == t->max_depth) {
b4ec74
+		for (uint64_t i = start; i <= end; i++)
b4ec74
+			fn(fn_data, i, trie_data_block_get(t,
b4ec74
+				(uint64_t *) node, i));
b4ec74
+
b4ec74
+		return end - start + 1;
b4ec74
+	}
b4ec74
+
b4ec74
+	uint8_t parent_node_bit_off = depth == 0 ?
b4ec74
+		t->key_size :
b4ec74
+		trie_get_node_bit_offs(t, depth - 1);
b4ec74
+
b4ec74
+	uint64_t first_key_in_node = start &
b4ec74
+		(uint64_t) -1 << parent_node_bit_off;
b4ec74
+
b4ec74
+	uint8_t node_bit_off = trie_get_node_bit_offs(t, depth);
b4ec74
+	uint8_t node_key_bits = parent_node_bit_off - node_bit_off;
b4ec74
+	uint64_t mask = ((uint64_t) 1 << (node_key_bits)) - 1;
b4ec74
+	uint64_t start_index = (start >> node_bit_off) & mask;
b4ec74
+	uint64_t end_index = (end >> node_bit_off) & mask;
b4ec74
+	uint64_t child_key_count = (uint64_t) 1 << node_bit_off;
b4ec74
+
b4ec74
+	uint64_t count = 0;
b4ec74
+
b4ec74
+	for (uint64_t i = start_index; i <= end_index; i++) {
b4ec74
+		uint64_t child_start = first_key_in_node + i * child_key_count;
b4ec74
+		uint64_t child_end = first_key_in_node +
b4ec74
+			(i + 1) * child_key_count - 1;
b4ec74
+
b4ec74
+		if (child_start < start)
b4ec74
+			child_start = start;
b4ec74
+		if (child_end > end)
b4ec74
+			child_end = end;
b4ec74
+
b4ec74
+		count += trie_iterate_keys_node(t, fn, fn_data,
b4ec74
+			((void **) node)[i], child_start, child_end,
b4ec74
+			depth + 1);
b4ec74
+	}
b4ec74
+
b4ec74
+	return count;
b4ec74
+}
b4ec74
+
b4ec74
+uint64_t trie_iterate_keys(struct trie *t, uint64_t start, uint64_t end,
b4ec74
+                           trie_iterate_fn fn, void *fn_data)
b4ec74
+{
b4ec74
+	return trie_iterate_keys_node(t, fn, fn_data, t->data,
b4ec74
+		start, end, 0);
b4ec74
+}
b4ec74
+
b4ec74
+static void
b4ec74
+trie_free_node(struct trie *t, void *node, uint8_t depth)
b4ec74
+{
b4ec74
+	if (!node)
b4ec74
+		return;
b4ec74
+
b4ec74
+	if (depth >= t->max_depth)
b4ec74
+		goto free_node;
b4ec74
+
b4ec74
+	size_t sz = 1 << (trie_get_node_size(t, depth) - ptr_sz_lg);
b4ec74
+	for (size_t i = 0; i < sz; i++)
b4ec74
+		trie_free_node(t, ((void **) node)[i], depth + 1);
b4ec74
+
b4ec74
+free_node:
b4ec74
+	free(node);
b4ec74
+}
b4ec74
+
b4ec74
+void
b4ec74
+trie_free(struct trie *t)
b4ec74
+{
b4ec74
+	trie_free_node(t, t->data, 0);
b4ec74
+	free(t);
b4ec74
+}
b4ec74
Index: strace-5.7/trie.h
b4ec74
===================================================================
b4ec74
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
b4ec74
+++ strace-5.7/trie.h	2020-09-09 15:50:18.019903763 +0200
b4ec74
@@ -0,0 +1,92 @@
b4ec74
+/*
b4ec74
+ * Simple trie interface
b4ec74
+ *
b4ec74
+ * Copyright (c) 2020 Ákos Uzonyi <uzonyi.akos@gmail.com>
b4ec74
+ * All rights reserved.
b4ec74
+ *
b4ec74
+ * SPDX-License-Identifier: LGPL-2.1-or-later
b4ec74
+ */
b4ec74
+
b4ec74
+#ifndef STRACE_TRIE_H
b4ec74
+#define STRACE_TRIE_H
b4ec74
+
b4ec74
+#include <stdbool.h>
b4ec74
+#include <stdint.h>
b4ec74
+
b4ec74
+/**
b4ec74
+ * Trie control structure.
b4ec74
+ * Trie implemented here has the following properties:
b4ec74
+ *  * It allows storing values of the same size, the size can vary from 1 bit to
b4ec74
+ *    64 bit values (only power of 2 sizes are allowed).
b4ec74
+ *  * The key can be up to 64 bits in size.
b4ec74
+ *  * It has separate configuration for node size and data block size.
b4ec74
+ *
b4ec74
+ * How bits of key are used for different node levels:
b4ec74
+ *
b4ec74
+ *   highest bits                                                  lowest bits
b4ec74
+ *  | node_key_bits | node_key_bits | ... | <remainder> | data_block_key_bits |
b4ec74
+ *  \_________________________________________________________________________/
b4ec74
+ *                                 key_size
b4ec74
+ *
b4ec74
+ * So, the remainder is used on the lowest non-data node level.
b4ec74
+ *
b4ec74
+ * As of now, it doesn't implement any mechanisms for resizing/changing key
b4ec74
+ * size.  De-fragmentation is also unsupported currently.
b4ec74
+ */
b4ec74
+struct trie {
b4ec74
+	/** Return value of trie_get if key is not found */
b4ec74
+	uint64_t empty_value;
b4ec74
+
b4ec74
+	/** Pointer to root node */
b4ec74
+	void *data;
b4ec74
+
b4ec74
+	/** Key size in bits (0..64). */
b4ec74
+	uint8_t key_size;
b4ec74
+
b4ec74
+	/**
b4ec74
+	 * Size of the stored values in log2 bits (0..6).
b4ec74
+	 * (6: 64 bit values, 5: 32 bit values, ...)
b4ec74
+	 */
b4ec74
+	uint8_t item_size_lg;
b4ec74
+
b4ec74
+	/**
b4ec74
+	 * Number of bits in the key that make a symbol for a node.
b4ec74
+	 * (equals to log2 of the child count of the node)
b4ec74
+	 */
b4ec74
+	uint8_t node_key_bits;
b4ec74
+
b4ec74
+	/**
b4ec74
+	 * Number of bits in the key that make a symbol for the data block (leaf).
b4ec74
+	 * (equals to log2 of the value count stored in a data block)
b4ec74
+	 */
b4ec74
+	uint8_t data_block_key_bits;
b4ec74
+
b4ec74
+	/** The depth of the data block. Calculated from the values above */
b4ec74
+	uint8_t max_depth;
b4ec74
+};
b4ec74
+
b4ec74
+struct trie* trie_create(uint8_t key_size, uint8_t item_size_lg,
b4ec74
+			uint8_t node_key_bits, uint8_t data_block_key_bits,
b4ec74
+			uint64_t empty_value);
b4ec74
+
b4ec74
+bool trie_set(struct trie *t, uint64_t key, uint64_t val);
b4ec74
+uint64_t trie_get(struct trie *t, uint64_t key);
b4ec74
+
b4ec74
+typedef void (*trie_iterate_fn)(void *data, uint64_t key, uint64_t val);
b4ec74
+
b4ec74
+/**
b4ec74
+ * Calls trie_iterate_fn for each key-value pair where
b4ec74
+ * key is inside the [start, end] interval (inclusive).
b4ec74
+ *
b4ec74
+ * @param t        The trie.
b4ec74
+ * @param start    The start of the key interval (inclusive).
b4ec74
+ * @param end      The end of the key interval (inclusive).
b4ec74
+ * @param fn       The function to be called.
b4ec74
+ * @param fn_data  The value to be passed to fn.
b4ec74
+ */
b4ec74
+uint64_t trie_iterate_keys(struct trie *t, uint64_t start, uint64_t end,
b4ec74
+			    trie_iterate_fn fn, void *fn_data);
b4ec74
+
b4ec74
+void trie_free(struct trie *t);
b4ec74
+
b4ec74
+#endif /* !STRACE_TRIE_H */
b4ec74
Index: strace-5.7/Makefile.in
b4ec74
===================================================================
b4ec74
--- strace-5.7.orig/Makefile.in	2020-09-09 15:50:13.484900519 +0200
b4ec74
+++ strace-5.7/Makefile.in	2020-09-09 15:54:59.569105143 +0200
b4ec74
@@ -344,8 +344,8 @@
b4ec74
 	nlattr.c nlattr.h nsfs.c nsfs.h nsig.h numa.c number_set.c \
b4ec74
 	number_set.h oldstat.c open.c open_tree.c or1k_atomic.c \
b4ec74
 	pathtrace.c perf.c perf_event_struct.h perf_ioctl.c \
b4ec74
-	personality.c pidfd_getfd.c pidfd_open.c pkeys.c poll.c \
b4ec74
-	prctl.c print_aio_sigset.c print_dev_t.c print_fields.h \
b4ec74
+	personality.c pidfd_getfd.c pidfd_open.c pidns.c pkeys.c \
b4ec74
+	poll.c prctl.c print_aio_sigset.c print_dev_t.c print_fields.h \
b4ec74
 	print_group_req.c print_ifindex.c print_instruction_pointer.c \
b4ec74
 	print_kernel_version.c print_mac.c print_mq_attr.c \
b4ec74
 	print_msgbuf.c print_sg_req_info.c print_sigevent.c \
b4ec74
@@ -369,10 +369,10 @@
b4ec74
 	string_to_uint.h swapon.c sync_file_range.c sync_file_range2.c \
b4ec74
 	syscall.c sysctl.c sysent.h sysent_shorthand_defs.h \
b4ec74
 	sysent_shorthand_undefs.h sysinfo.c syslog.c sysmips.c term.c \
b4ec74
-	time.c times.c trace_event.h truncate.c ubi.c ucopy.c uid.c \
b4ec74
-	uid16.c umask.c umount.c uname.c upeek.c upoke.c userfaultfd.c \
b4ec74
-	ustat.c util.c utime.c utimes.c v4l2.c wait.c wait.h \
b4ec74
-	watchdog_ioctl.c xattr.c xfs_quota_stat.h xgetdents.c \
b4ec74
+	time.c times.c trace_event.h trie.c trie.h truncate.c ubi.c \
b4ec74
+	ucopy.c uid.c uid16.c umask.c umount.c uname.c upeek.c upoke.c \
b4ec74
+	userfaultfd.c ustat.c util.c utime.c utimes.c v4l2.c wait.c \
b4ec74
+	wait.h watchdog_ioctl.c xattr.c xfs_quota_stat.h xgetdents.c \
b4ec74
 	xgetdents.h xlat.c xlat.h xmalloc.c xmalloc.h xstring.h \
b4ec74
 	types/cryptouser.h types/evdev.h types/io_uring.h \
b4ec74
 	types/openat2.h types/rtnl_link.h types/rtnl_mdb.h \
b4ec74
@@ -487,8 +487,9 @@
b4ec74
 	libstrace_a-perf_ioctl.$(OBJEXT) \
b4ec74
 	libstrace_a-personality.$(OBJEXT) \
b4ec74
 	libstrace_a-pidfd_getfd.$(OBJEXT) \
b4ec74
-	libstrace_a-pidfd_open.$(OBJEXT) libstrace_a-pkeys.$(OBJEXT) \
b4ec74
-	libstrace_a-poll.$(OBJEXT) libstrace_a-prctl.$(OBJEXT) \
b4ec74
+	libstrace_a-pidfd_open.$(OBJEXT) libstrace_a-pidns.$(OBJEXT) \
b4ec74
+	libstrace_a-pkeys.$(OBJEXT) libstrace_a-poll.$(OBJEXT) \
b4ec74
+	libstrace_a-prctl.$(OBJEXT) \
b4ec74
 	libstrace_a-print_aio_sigset.$(OBJEXT) \
b4ec74
 	libstrace_a-print_dev_t.$(OBJEXT) \
b4ec74
 	libstrace_a-print_group_req.$(OBJEXT) \
b4ec74
@@ -553,15 +554,15 @@
b4ec74
 	libstrace_a-sysinfo.$(OBJEXT) libstrace_a-syslog.$(OBJEXT) \
b4ec74
 	libstrace_a-sysmips.$(OBJEXT) libstrace_a-term.$(OBJEXT) \
b4ec74
 	libstrace_a-time.$(OBJEXT) libstrace_a-times.$(OBJEXT) \
b4ec74
-	libstrace_a-truncate.$(OBJEXT) libstrace_a-ubi.$(OBJEXT) \
b4ec74
-	libstrace_a-ucopy.$(OBJEXT) libstrace_a-uid.$(OBJEXT) \
b4ec74
-	libstrace_a-uid16.$(OBJEXT) libstrace_a-umask.$(OBJEXT) \
b4ec74
-	libstrace_a-umount.$(OBJEXT) libstrace_a-uname.$(OBJEXT) \
b4ec74
-	libstrace_a-upeek.$(OBJEXT) libstrace_a-upoke.$(OBJEXT) \
b4ec74
-	libstrace_a-userfaultfd.$(OBJEXT) libstrace_a-ustat.$(OBJEXT) \
b4ec74
-	libstrace_a-util.$(OBJEXT) libstrace_a-utime.$(OBJEXT) \
b4ec74
-	libstrace_a-utimes.$(OBJEXT) libstrace_a-v4l2.$(OBJEXT) \
b4ec74
-	libstrace_a-wait.$(OBJEXT) \
b4ec74
+	libstrace_a-trie.$(OBJEXT) libstrace_a-truncate.$(OBJEXT) \
b4ec74
+	libstrace_a-ubi.$(OBJEXT) libstrace_a-ucopy.$(OBJEXT) \
b4ec74
+	libstrace_a-uid.$(OBJEXT) libstrace_a-uid16.$(OBJEXT) \
b4ec74
+	libstrace_a-umask.$(OBJEXT) libstrace_a-umount.$(OBJEXT) \
b4ec74
+	libstrace_a-uname.$(OBJEXT) libstrace_a-upeek.$(OBJEXT) \
b4ec74
+	libstrace_a-upoke.$(OBJEXT) libstrace_a-userfaultfd.$(OBJEXT) \
b4ec74
+	libstrace_a-ustat.$(OBJEXT) libstrace_a-util.$(OBJEXT) \
b4ec74
+	libstrace_a-utime.$(OBJEXT) libstrace_a-utimes.$(OBJEXT) \
b4ec74
+	libstrace_a-v4l2.$(OBJEXT) libstrace_a-wait.$(OBJEXT) \
b4ec74
 	libstrace_a-watchdog_ioctl.$(OBJEXT) \
b4ec74
 	libstrace_a-xattr.$(OBJEXT) libstrace_a-xgetdents.$(OBJEXT) \
b4ec74
 	libstrace_a-xlat.$(OBJEXT) libstrace_a-xmalloc.$(OBJEXT) \
b4ec74
@@ -834,6 +835,7 @@
b4ec74
 	./$(DEPDIR)/libstrace_a-personality.Po \
b4ec74
 	./$(DEPDIR)/libstrace_a-pidfd_getfd.Po \
b4ec74
 	./$(DEPDIR)/libstrace_a-pidfd_open.Po \
b4ec74
+	./$(DEPDIR)/libstrace_a-pidns.Po \
b4ec74
 	./$(DEPDIR)/libstrace_a-pkeys.Po \
b4ec74
 	./$(DEPDIR)/libstrace_a-poll.Po \
b4ec74
 	./$(DEPDIR)/libstrace_a-prctl.Po \
b4ec74
@@ -924,6 +926,7 @@
b4ec74
 	./$(DEPDIR)/libstrace_a-term.Po \
b4ec74
 	./$(DEPDIR)/libstrace_a-time.Po \
b4ec74
 	./$(DEPDIR)/libstrace_a-times.Po \
b4ec74
+	./$(DEPDIR)/libstrace_a-trie.Po \
b4ec74
 	./$(DEPDIR)/libstrace_a-truncate.Po \
b4ec74
 	./$(DEPDIR)/libstrace_a-ubi.Po \
b4ec74
 	./$(DEPDIR)/libstrace_a-ucopy.Po \
b4ec74
@@ -1829,8 +1832,8 @@
b4ec74
 	nlattr.c nlattr.h nsfs.c nsfs.h nsig.h numa.c number_set.c \
b4ec74
 	number_set.h oldstat.c open.c open_tree.c or1k_atomic.c \
b4ec74
 	pathtrace.c perf.c perf_event_struct.h perf_ioctl.c \
b4ec74
-	personality.c pidfd_getfd.c pidfd_open.c pkeys.c poll.c \
b4ec74
-	prctl.c print_aio_sigset.c print_dev_t.c print_fields.h \
b4ec74
+	personality.c pidfd_getfd.c pidfd_open.c pidns.c pkeys.c \
b4ec74
+	poll.c prctl.c print_aio_sigset.c print_dev_t.c print_fields.h \
b4ec74
 	print_group_req.c print_ifindex.c print_instruction_pointer.c \
b4ec74
 	print_kernel_version.c print_mac.c print_mq_attr.c \
b4ec74
 	print_msgbuf.c print_sg_req_info.c print_sigevent.c \
b4ec74
@@ -1854,10 +1857,10 @@
b4ec74
 	string_to_uint.h swapon.c sync_file_range.c sync_file_range2.c \
b4ec74
 	syscall.c sysctl.c sysent.h sysent_shorthand_defs.h \
b4ec74
 	sysent_shorthand_undefs.h sysinfo.c syslog.c sysmips.c term.c \
b4ec74
-	time.c times.c trace_event.h truncate.c ubi.c ucopy.c uid.c \
b4ec74
-	uid16.c umask.c umount.c uname.c upeek.c upoke.c userfaultfd.c \
b4ec74
-	ustat.c util.c utime.c utimes.c v4l2.c wait.c wait.h \
b4ec74
-	watchdog_ioctl.c xattr.c xfs_quota_stat.h xgetdents.c \
b4ec74
+	time.c times.c trace_event.h trie.c trie.h truncate.c ubi.c \
b4ec74
+	ucopy.c uid.c uid16.c umask.c umount.c uname.c upeek.c upoke.c \
b4ec74
+	userfaultfd.c ustat.c util.c utime.c utimes.c v4l2.c wait.c \
b4ec74
+	wait.h watchdog_ioctl.c xattr.c xfs_quota_stat.h xgetdents.c \
b4ec74
 	xgetdents.h xlat.c xlat.h xmalloc.c xmalloc.h xstring.h \
b4ec74
 	$(TYPES_HEADER_FILES) $(strace_SOURCES_check) $(am__append_1) \
b4ec74
 	$(am__append_2) $(am__append_7)
b4ec74
@@ -2899,6 +2902,7 @@
b4ec74
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libstrace_a-personality.Po@am__quote@ # am--include-marker
b4ec74
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libstrace_a-pidfd_getfd.Po@am__quote@ # am--include-marker
b4ec74
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libstrace_a-pidfd_open.Po@am__quote@ # am--include-marker
b4ec74
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libstrace_a-pidns.Po@am__quote@ # am--include-marker
b4ec74
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libstrace_a-pkeys.Po@am__quote@ # am--include-marker
b4ec74
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libstrace_a-poll.Po@am__quote@ # am--include-marker
b4ec74
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libstrace_a-prctl.Po@am__quote@ # am--include-marker
b4ec74
@@ -2989,6 +2993,7 @@
b4ec74
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libstrace_a-term.Po@am__quote@ # am--include-marker
b4ec74
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libstrace_a-time.Po@am__quote@ # am--include-marker
b4ec74
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libstrace_a-times.Po@am__quote@ # am--include-marker
b4ec74
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libstrace_a-trie.Po@am__quote@ # am--include-marker
b4ec74
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libstrace_a-truncate.Po@am__quote@ # am--include-marker
b4ec74
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libstrace_a-ubi.Po@am__quote@ # am--include-marker
b4ec74
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libstrace_a-ucopy.Po@am__quote@ # am--include-marker
b4ec74
@@ -6015,6 +6020,20 @@
b4ec74
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
b4ec74
 @am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libstrace_a_CPPFLAGS) $(CPPFLAGS) $(libstrace_a_CFLAGS) $(CFLAGS) -c -o libstrace_a-pidfd_open.obj `if test -f 'pidfd_open.c'; then $(CYGPATH_W) 'pidfd_open.c'; else $(CYGPATH_W) '$(srcdir)/pidfd_open.c'; fi`
b4ec74
 
b4ec74
+libstrace_a-pidns.o: pidns.c
b4ec74
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libstrace_a_CPPFLAGS) $(CPPFLAGS) $(libstrace_a_CFLAGS) $(CFLAGS) -MT libstrace_a-pidns.o -MD -MP -MF $(DEPDIR)/libstrace_a-pidns.Tpo -c -o libstrace_a-pidns.o `test -f 'pidns.c' || echo '$(srcdir)/'`pidns.c
b4ec74
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libstrace_a-pidns.Tpo $(DEPDIR)/libstrace_a-pidns.Po
b4ec74
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='pidns.c' object='libstrace_a-pidns.o' libtool=no @AMDEPBACKSLASH@
b4ec74
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
b4ec74
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libstrace_a_CPPFLAGS) $(CPPFLAGS) $(libstrace_a_CFLAGS) $(CFLAGS) -c -o libstrace_a-pidns.o `test -f 'pidns.c' || echo '$(srcdir)/'`pidns.c
b4ec74
+
b4ec74
+libstrace_a-pidns.obj: pidns.c
b4ec74
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libstrace_a_CPPFLAGS) $(CPPFLAGS) $(libstrace_a_CFLAGS) $(CFLAGS) -MT libstrace_a-pidns.obj -MD -MP -MF $(DEPDIR)/libstrace_a-pidns.Tpo -c -o libstrace_a-pidns.obj `if test -f 'pidns.c'; then $(CYGPATH_W) 'pidns.c'; else $(CYGPATH_W) '$(srcdir)/pidns.c'; fi`
b4ec74
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libstrace_a-pidns.Tpo $(DEPDIR)/libstrace_a-pidns.Po
b4ec74
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='pidns.c' object='libstrace_a-pidns.obj' libtool=no @AMDEPBACKSLASH@
b4ec74
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
b4ec74
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libstrace_a_CPPFLAGS) $(CPPFLAGS) $(libstrace_a_CFLAGS) $(CFLAGS) -c -o libstrace_a-pidns.obj `if test -f 'pidns.c'; then $(CYGPATH_W) 'pidns.c'; else $(CYGPATH_W) '$(srcdir)/pidns.c'; fi`
b4ec74
+
b4ec74
 libstrace_a-pkeys.o: pkeys.c
b4ec74
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libstrace_a_CPPFLAGS) $(CPPFLAGS) $(libstrace_a_CFLAGS) $(CFLAGS) -MT libstrace_a-pkeys.o -MD -MP -MF $(DEPDIR)/libstrace_a-pkeys.Tpo -c -o libstrace_a-pkeys.o `test -f 'pkeys.c' || echo '$(srcdir)/'`pkeys.c
b4ec74
 @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libstrace_a-pkeys.Tpo $(DEPDIR)/libstrace_a-pkeys.Po
b4ec74
@@ -7275,6 +7294,20 @@
b4ec74
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
b4ec74
 @am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libstrace_a_CPPFLAGS) $(CPPFLAGS) $(libstrace_a_CFLAGS) $(CFLAGS) -c -o libstrace_a-times.obj `if test -f 'times.c'; then $(CYGPATH_W) 'times.c'; else $(CYGPATH_W) '$(srcdir)/times.c'; fi`
b4ec74
 
b4ec74
+libstrace_a-trie.o: trie.c
b4ec74
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libstrace_a_CPPFLAGS) $(CPPFLAGS) $(libstrace_a_CFLAGS) $(CFLAGS) -MT libstrace_a-trie.o -MD -MP -MF $(DEPDIR)/libstrace_a-trie.Tpo -c -o libstrace_a-trie.o `test -f 'trie.c' || echo '$(srcdir)/'`trie.c
b4ec74
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libstrace_a-trie.Tpo $(DEPDIR)/libstrace_a-trie.Po
b4ec74
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='trie.c' object='libstrace_a-trie.o' libtool=no @AMDEPBACKSLASH@
b4ec74
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
b4ec74
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libstrace_a_CPPFLAGS) $(CPPFLAGS) $(libstrace_a_CFLAGS) $(CFLAGS) -c -o libstrace_a-trie.o `test -f 'trie.c' || echo '$(srcdir)/'`trie.c
b4ec74
+
b4ec74
+libstrace_a-trie.obj: trie.c
b4ec74
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libstrace_a_CPPFLAGS) $(CPPFLAGS) $(libstrace_a_CFLAGS) $(CFLAGS) -MT libstrace_a-trie.obj -MD -MP -MF $(DEPDIR)/libstrace_a-trie.Tpo -c -o libstrace_a-trie.obj `if test -f 'trie.c'; then $(CYGPATH_W) 'trie.c'; else $(CYGPATH_W) '$(srcdir)/trie.c'; fi`
b4ec74
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libstrace_a-trie.Tpo $(DEPDIR)/libstrace_a-trie.Po
b4ec74
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='trie.c' object='libstrace_a-trie.obj' libtool=no @AMDEPBACKSLASH@
b4ec74
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
b4ec74
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libstrace_a_CPPFLAGS) $(CPPFLAGS) $(libstrace_a_CFLAGS) $(CFLAGS) -c -o libstrace_a-trie.obj `if test -f 'trie.c'; then $(CYGPATH_W) 'trie.c'; else $(CYGPATH_W) '$(srcdir)/trie.c'; fi`
b4ec74
+
b4ec74
 libstrace_a-truncate.o: truncate.c
b4ec74
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libstrace_a_CPPFLAGS) $(CPPFLAGS) $(libstrace_a_CFLAGS) $(CFLAGS) -MT libstrace_a-truncate.o -MD -MP -MF $(DEPDIR)/libstrace_a-truncate.Tpo -c -o libstrace_a-truncate.o `test -f 'truncate.c' || echo '$(srcdir)/'`truncate.c
b4ec74
 @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libstrace_a-truncate.Tpo $(DEPDIR)/libstrace_a-truncate.Po
b4ec74
@@ -8411,6 +8444,7 @@
b4ec74
 	-rm -f ./$(DEPDIR)/libstrace_a-personality.Po
b4ec74
 	-rm -f ./$(DEPDIR)/libstrace_a-pidfd_getfd.Po
b4ec74
 	-rm -f ./$(DEPDIR)/libstrace_a-pidfd_open.Po
b4ec74
+	-rm -f ./$(DEPDIR)/libstrace_a-pidns.Po
b4ec74
 	-rm -f ./$(DEPDIR)/libstrace_a-pkeys.Po
b4ec74
 	-rm -f ./$(DEPDIR)/libstrace_a-poll.Po
b4ec74
 	-rm -f ./$(DEPDIR)/libstrace_a-prctl.Po
b4ec74
@@ -8501,6 +8535,7 @@
b4ec74
 	-rm -f ./$(DEPDIR)/libstrace_a-term.Po
b4ec74
 	-rm -f ./$(DEPDIR)/libstrace_a-time.Po
b4ec74
 	-rm -f ./$(DEPDIR)/libstrace_a-times.Po
b4ec74
+	-rm -f ./$(DEPDIR)/libstrace_a-trie.Po
b4ec74
 	-rm -f ./$(DEPDIR)/libstrace_a-truncate.Po
b4ec74
 	-rm -f ./$(DEPDIR)/libstrace_a-ubi.Po
b4ec74
 	-rm -f ./$(DEPDIR)/libstrace_a-ucopy.Po
b4ec74
@@ -8796,6 +8831,7 @@
b4ec74
 	-rm -f ./$(DEPDIR)/libstrace_a-personality.Po
b4ec74
 	-rm -f ./$(DEPDIR)/libstrace_a-pidfd_getfd.Po
b4ec74
 	-rm -f ./$(DEPDIR)/libstrace_a-pidfd_open.Po
b4ec74
+	-rm -f ./$(DEPDIR)/libstrace_a-pidns.Po
b4ec74
 	-rm -f ./$(DEPDIR)/libstrace_a-pkeys.Po
b4ec74
 	-rm -f ./$(DEPDIR)/libstrace_a-poll.Po
b4ec74
 	-rm -f ./$(DEPDIR)/libstrace_a-prctl.Po
b4ec74
@@ -8886,6 +8922,7 @@
b4ec74
 	-rm -f ./$(DEPDIR)/libstrace_a-term.Po
b4ec74
 	-rm -f ./$(DEPDIR)/libstrace_a-time.Po
b4ec74
 	-rm -f ./$(DEPDIR)/libstrace_a-times.Po
b4ec74
+	-rm -f ./$(DEPDIR)/libstrace_a-trie.Po
b4ec74
 	-rm -f ./$(DEPDIR)/libstrace_a-truncate.Po
b4ec74
 	-rm -f ./$(DEPDIR)/libstrace_a-ubi.Po
b4ec74
 	-rm -f ./$(DEPDIR)/libstrace_a-ucopy.Po