[PATCH v1] strace: Enhance --string-limit/-s to remove max string length limit

Gautam Menghani gautammenghani201 at gmail.com
Sun Jan 21 10:46:02 UTC 2024


Enhance the -s STRSIZE/--string-limit=STRSIZE option to provide the
ability to remove the max string length limit with the value argument
'inf'. This patch resolves issue 269 on github.

Signed-off-by: Gautam Menghani <gum3ng at protonmail.com>
---
 NEWS               |  2 ++
 src/btrfs.c        |  2 +-
 src/defs.h         |  3 +++
 src/dm.c           |  6 +++---
 src/execve.c       |  3 +--
 src/netlink.c      |  2 +-
 src/nlattr.c       |  2 +-
 src/strace.c       | 13 ++++++++++---
 src/util.c         | 31 ++++++++++++++++++++++++-------
 tests/gen_tests.in |  1 +
 tests/truncate.c   | 20 ++++++++++++--------
 11 files changed, 59 insertions(+), 26 deletions(-)

diff --git a/NEWS b/NEWS
index bd66e7069..02337ec1d 100644
--- a/NEWS
+++ b/NEWS
@@ -5,6 +5,8 @@ Noteworthy changes in release ?.? (????-??-??)
   * Implemented -kk/--stack-traces=source option for libdw-based stack tracing.
   * Updated lists of BPF_*, BTRFS_*, IORING_*, KVM_*, LANDLOCK_*, PR_*,
     and TCP_* constants.
+  * Enhance --string-limit/-s to introduce a new value argument ('inf') to remove
+    max string length limit.
 
 * Bug fixes
   * Fix strace -r during the first second after booting to show correct relative
diff --git a/src/btrfs.c b/src/btrfs.c
index 31ee871b3..c6408c94a 100644
--- a/src/btrfs.c
+++ b/src/btrfs.c
@@ -381,7 +381,7 @@ decode_search_arg_buf(struct tcb *tcp, kernel_ulong_t buf_addr, uint64_t buf_siz
 			struct btrfs_ioctl_search_header sh;
 			uint64_t addr = buf_addr + off;
 			if (addr < buf_addr || off + sizeof(sh) > buf_size ||
-			    i > max_strlen) {
+			    truncation_needed(i, max_strlen + 1)) {
 				tprint_more_data_follows();
 				break;
 			}
diff --git a/src/defs.h b/src/defs.h
index 6f1f25680..8005112c8 100644
--- a/src/defs.h
+++ b/src/defs.h
@@ -556,12 +556,15 @@ extern enum stack_trace_modes stack_trace_mode;
 #  define stack_trace_mode STACK_TRACE_OFF
 # endif
 extern unsigned max_strlen;
+extern bool truncate_output;
 extern unsigned os_release;
 # undef KERNEL_VERSION
 # define KERNEL_VERSION(a, b, c) (((a) << 16) + ((b) << 8) + (c))
 
 extern int read_int_from_file(const char *, int *);
 
+extern bool truncation_needed(unsigned int size, unsigned int limit);
+
 extern void set_sortby(const char *);
 extern int set_overhead(const char *);
 extern void set_count_summary_columns(const char *columns);
diff --git a/src/dm.c b/src/dm.c
index 2977eac68..0f4cee527 100644
--- a/src/dm.c
+++ b/src/dm.c
@@ -190,7 +190,7 @@ dm_decode_dm_target_spec(struct tcb *const tcp, const kernel_ulong_t addr,
 		if (offset_end <= offset || offset_end > ioc->data_size)
 			goto misplaced;
 
-		if (i >= max_strlen) {
+		if (truncation_needed(i, max_strlen)) {
 			tprint_more_data_follows();
 			break;
 		}
@@ -323,7 +323,7 @@ dm_decode_dm_name_list(struct tcb *const tcp, const kernel_ulong_t addr,
 		if (offset_end <= offset || offset_end > ioc->data_size)
 			goto misplaced;
 
-		if (count >= max_strlen) {
+		if (truncation_needed(count, max_strlen)) {
 			tprint_more_data_follows();
 			break;
 		}
@@ -413,7 +413,7 @@ dm_decode_dm_target_versions(struct tcb *const tcp, const kernel_ulong_t addr,
 		if (offset_end <= offset || offset_end > ioc->data_size)
 			goto misplaced;
 
-		if (count >= max_strlen) {
+		if (truncation_needed(count, max_strlen)) {
 			tprint_more_data_follows();
 			break;
 		}
diff --git a/src/execve.c b/src/execve.c
index a9224543b..a85f5feec 100644
--- a/src/execve.c
+++ b/src/execve.c
@@ -52,8 +52,7 @@ printargv(struct tcb *const tcp, kernel_ulong_t addr)
 			break;
 		if (n != 0)
 			tprint_array_next();
-
-		if (abbrev(tcp) && n >= max_strlen) {
+		if (abbrev(tcp) && truncation_needed(n, max_strlen)) {
 			tprint_more_data_follows();
 			break;
 		}
diff --git a/src/netlink.c b/src/netlink.c
index 0e31168c3..a2f2cfa8e 100644
--- a/src/netlink.c
+++ b/src/netlink.c
@@ -684,7 +684,7 @@ decode_netlink(struct tcb *const tcp,
 	for (unsigned int elt = 0;
 	     fetch_nlmsghdr(tcp, &nlmsghdr, addr, len, is_array);
 	     ++elt) {
-		if (abbrev(tcp) && elt == max_strlen) {
+		if (abbrev(tcp) && truncation_needed(elt, max_strlen)) {
 			tprint_more_data_follows();
 			break;
 		}
diff --git a/src/nlattr.c b/src/nlattr.c
index 1fb394d7c..762fd7a9d 100644
--- a/src/nlattr.c
+++ b/src/nlattr.c
@@ -128,7 +128,7 @@ decode_nlattr(struct tcb *const tcp,
 	for (unsigned int elt = 0;
 	     fetch_nlattr(tcp, &nla, addr, len, is_array);
 	     ++elt) {
-		if (abbrev(tcp) && elt == max_strlen) {
+		if (abbrev(tcp) && truncation_needed(elt, max_strlen)) {
 			tprint_more_data_follows();
 			break;
 		}
diff --git a/src/strace.c b/src/strace.c
index 780e51e91..a4c4b6ec8 100644
--- a/src/strace.c
+++ b/src/strace.c
@@ -27,6 +27,7 @@
 #include <locale.h>
 #include <sys/utsname.h>
 #include <sys/prctl.h>
+#include <ctype.h>
 
 #include "kill_save_errno.h"
 #include "exitkill.h"
@@ -154,6 +155,7 @@ static uid_t run_uid;
 static gid_t run_gid;
 
 unsigned int max_strlen = DEFAULT_STRLEN;
+bool truncate_output = true;
 static int acolumn = DEFAULT_ACOLUMN;
 static char *acolumn_spaces;
 
@@ -2562,10 +2564,15 @@ init(int argc, char *argv[])
 				error_opt_arg(c, lopt, optarg);
 			break;
 		case 's':
-			i = string_to_uint(optarg);
-			if (i < 0 || (unsigned int) i > -1U / 4)
+			if (isdigit(*optarg)) {
+				i = string_to_uint(optarg);
+				if (i < 0 || (unsigned int) i > -1U / 4)
+					error_opt_arg(c, lopt, optarg);
+				max_strlen = i;
+			} else if (strcmp(optarg, "inf") == 0)
+				truncate_output = false;
+			else
 				error_opt_arg(c, lopt, optarg);
-			max_strlen = i;
 			break;
 		case 'S':
 			set_sortby(optarg);
diff --git a/src/util.c b/src/util.c
index 92c0577ce..68fb0277e 100644
--- a/src/util.c
+++ b/src/util.c
@@ -22,6 +22,7 @@
 # include <sys/xattr.h>
 #endif
 #include <sys/uio.h>
+#include <sys/sysinfo.h>
 
 #include "largefile_wrappers.h"
 #include "number_set.h"
@@ -1258,30 +1259,39 @@ printstr_ex(struct tcb *const tcp, const kernel_ulong_t addr,
 	static char *str;
 	static char *outstr;
 
-	unsigned int size;
+	unsigned long size;
 	unsigned int style = user_style;
+	unsigned long max_len = max_strlen;
 	int rc;
 	int ellipsis;
+	struct sysinfo info;
 
 	if (!addr) {
 		tprint_null();
 		return -1;
 	}
+
+	if (!truncate_output) {
+		sysinfo(&info);
+		max_len = info.totalram;
+	}
+
 	/* Allocate static buffers if they are not allocated yet. */
+
 	if (!str) {
 		const unsigned int outstr_size =
-			4 * max_strlen + /* for quotes and NUL */ 3;
+			4 * max_len + /* for quotes and NUL */ 3;
 		/*
 		 * We can assume that outstr_size / 4 == max_strlen
 		 * since we have a guarantee that max_strlen <= -1U / 4.
 		 */
 
-		str = xmalloc(max_strlen + 1);
+		str = xmalloc(max_len + 1);
 		outstr = xmalloc(outstr_size);
 	}
 
 	/* Fetch one byte more because string_quote may look one byte ahead. */
-	size = max_strlen + 1;
+	size = max_len + 1;
 
 	if (size > len)
 		size = len;
@@ -1295,7 +1305,7 @@ printstr_ex(struct tcb *const tcp, const kernel_ulong_t addr,
 		return rc;
 	}
 
-	if (size > max_strlen)
+	if (truncation_needed(size, max_strlen + 1))
 		size = max_strlen;
 	else
 		str[size] = '\xff';
@@ -1312,7 +1322,7 @@ printstr_ex(struct tcb *const tcp, const kernel_ulong_t addr,
 	ellipsis = string_quote(str, outstr, size, style, NULL)
 		   && len
 		   && ((style & (QUOTE_0_TERMINATED | QUOTE_EXPECT_TRAILING_0))
-		       || len > max_strlen);
+		       || truncation_needed(len, max_strlen + 1));
 
 	tprints_string(outstr);
 	if (ellipsis)
@@ -1774,7 +1784,7 @@ print_array_ex(struct tcb *const tcp,
 		if (cur == start_addr)
 			tprint_array_begin();
 
-		if (cur >= abbrev_end) {
+		if (truncation_needed(cur, abbrev_end)) {
 			tprint_more_data_follows();
 			cur = end_addr;
 			truncated = true;
@@ -1908,3 +1918,10 @@ read_int_from_file(const char *const fname, int *const pvalue)
 	*pvalue = (int) lval;
 	return 0;
 }
+
+bool truncation_needed(unsigned int size, unsigned int limit)
+{
+	if (truncate_output && size >= limit)
+		return true;
+	return false;
+}
diff --git a/tests/gen_tests.in b/tests/gen_tests.in
index bf2bcb2f2..4ee039709 100644
--- a/tests/gen_tests.in
+++ b/tests/gen_tests.in
@@ -1140,6 +1140,7 @@ trace_statfs	test_trace_expr '' -e%statfs
 trace_statfs_like	test_trace_expr '' -e%%statfs
 trie_test    run_prog
 truncate
+truncate -s inf
 truncate64
 ugetrlimit	-a28 'QUIRK:START-OF-TEST-OUTPUT:ugetrlimit(0x10 /* RLIMIT_??? */, NULL)'
 umask	-a11
diff --git a/tests/truncate.c b/tests/truncate.c
index d1ea3f683..f53935bce 100644
--- a/tests/truncate.c
+++ b/tests/truncate.c
@@ -17,18 +17,22 @@
 int
 main(void)
 {
-	static const char fname[] = "truncate\nfilename";
-	static const char qname[] = "truncate\\nfilename";
+	static const char * const fnames[] = {"truncate\nfilename",
+		"truncate\nfilename_p1\nfilename_p2\nfilename_p3"};
+	static const char * const qnames[] = {"truncate\\nfilename",
+		"truncate\\nfilename_p1\\nfilename_p2\\nfilename_p3"};
 	const kernel_ulong_t len = (kernel_ulong_t) 0xdefaced0badc0deULL;
 	long rc;
 
-	if (sizeof(len) > sizeof(long))
-		rc = truncate(fname, len);
-	else
-		rc = syscall(__NR_truncate, fname, len);
+	for (int i = 0; i < 2; i++) {
+		if (sizeof(len) > sizeof(long))
+			rc = truncate(fnames[i], len);
+		else
+			rc = syscall(__NR_truncate, fnames[i], len);
 
-	printf("truncate(\"%s\", %llu) = %s\n",
-	       qname, (unsigned long long) len, sprintrc(rc));
+		printf("truncate(\"%s\", %llu) = %s\n",
+			qnames[i], (unsigned long long) len, sprintrc(rc));
+	}
 
 	puts("+++ exited with 0 +++");
 	return 0;
-- 
2.34.1



More information about the Strace-devel mailing list