+++ /dev/null
-commit ba2cfac31ccfd0aa4c93524088d1be4fca3e68f6
-Author: ldv <ldv>
-Date: Mon Nov 10 22:53:02 2008 +0000
-
- 2008-10-23 Dmitry V. Levin <ldv@altlinux.org>
-
- Implement parsers for new linux syscalls.
- * desc.c (do_dup2, [LINUX] sys_dup3): New functions.
- (sys_dup2): Use do_dup2.
- [LINUX] (sys_epoll_create1): New function.
- [LINUX] (do_eventfd, sys_eventfd2): New functions.
- [LINUX] (sys_eventfd): Use do_eventfd.
- * net.c (do_pipe, [LINUX] sys_pipe2): New functions.
- (sys_pipe): Use do_pipe.
- * signal.c [LINUX] (do_signalfd, sys_signalfd4): New functions.
- [LINUX] (sys_signalfd): Use do_signalfd.
- * linux/syscall.h: Declare new sys_* functions.
- * linux/syscallent.h: Hook up signalfd4, eventfd2, epoll_create1,
- dup3, pipe2, inotify_init1.
- * linux/x86_64/syscallent.h: Hook up paccept, signalfd4, eventfd2,
- epoll_create1, dup3, pipe2, inotify_init1.
-
-diff --git a/desc.c b/desc.c
-index 8b8a894..222cb2b 100644
---- a/desc.c
-+++ b/desc.c
-@@ -242,6 +242,8 @@ int getlk;
- }
- #endif
-
-+extern const struct xlat open_mode_flags[];
-+
- /*
- * low bits of the open(2) flags define access mode,
- * other bits are real flags.
-@@ -250,7 +252,6 @@ static const char *
- sprint_open_modes(mode_t flags)
- {
- extern const struct xlat open_access_modes[];
-- extern const struct xlat open_mode_flags[];
- static char outstr[1024];
- const char *str = xlookup(open_access_modes, flags & 3);
- const char *sep = "";
-@@ -396,16 +397,33 @@ struct tcb *tcp;
- return 0;
- }
-
--int
--sys_dup2(tcp)
--struct tcb *tcp;
-+static int
-+do_dup2(struct tcb *tcp, int flags_arg)
- {
- if (entering(tcp)) {
- tprintf("%ld, %ld", tcp->u_arg[0], tcp->u_arg[1]);
-+ if (flags_arg >= 0) {
-+ tprintf(", ");
-+ printflags(open_mode_flags, tcp->u_arg[flags_arg], "O_???");
-+ }
- }
- return 0;
- }
-
-+int
-+sys_dup2(struct tcb *tcp)
-+{
-+ return do_dup2(tcp, -1);
-+}
-+
-+#ifdef LINUX
-+int
-+sys_dup3(struct tcb *tcp)
-+{
-+ return do_dup2(tcp, 2);
-+}
-+#endif
-+
- #if defined(ALPHA) || defined(FREEBSD) || defined(SUNOS4)
- int
- sys_getdtablesize(tcp)
-@@ -605,14 +623,21 @@ static struct xlat epollevents[] = {
- };
-
- int
--sys_epoll_create(tcp)
--struct tcb *tcp;
-+sys_epoll_create(struct tcb *tcp)
- {
- if (entering(tcp))
- tprintf("%ld", tcp->u_arg[0]);
- return 0;
- }
-
-+int
-+sys_epoll_create1(struct tcb *tcp)
-+{
-+ if (entering(tcp))
-+ printflags(open_mode_flags, tcp->u_arg[0], "O_???");
-+ return 0;
-+}
-+
- #ifdef HAVE_SYS_EPOLL_H
- static void
- print_epoll_event(ev)
-@@ -889,12 +914,28 @@ sys_pselect6(struct tcb *tcp)
- return rc;
- }
-
--int
--sys_eventfd(tcp)
--struct tcb *tcp;
-+static int
-+do_eventfd(struct tcb *tcp, int flags_arg)
- {
-- if (entering(tcp))
-+ if (entering(tcp)) {
- tprintf("%lu", tcp->u_arg[0]);
-+ if (flags_arg >= 0) {
-+ tprintf(", ");
-+ printflags(open_mode_flags, tcp->u_arg[flags_arg], "O_???");
-+ }
-+ }
- return 0;
- }
-+
-+int
-+sys_eventfd(struct tcb *tcp)
-+{
-+ return do_eventfd(tcp, -1);
-+}
-+
-+int
-+sys_eventfd2(struct tcb *tcp)
-+{
-+ return do_eventfd(tcp, 1);
-+}
- #endif
-diff --git a/linux/syscall.h b/linux/syscall.h
-index 96d6d2f..f8e4f20 100644
---- a/linux/syscall.h
-+++ b/linux/syscall.h
-@@ -105,6 +105,7 @@ int sys_io_setup(), sys_io_submit(), sys_io_cancel(), sys_io_getevents(), sys_io
- int sys_utimensat(), sys_epoll_pwait(), sys_signalfd(), sys_timerfd(), sys_eventfd();
- int sys_getcpu();
- int sys_fallocate(), sys_timerfd_create(), sys_timerfd_settime(), sys_timerfd_gettime();
-+int sys_signalfd4(), sys_eventfd2(), sys_epoll_create1(), sys_dup3(), sys_pipe2();
-
- /* sys_socketcall subcalls */
-
-diff --git a/linux/syscallent.h b/linux/syscallent.h
-index 59c9a72..53bd9b3 100644
---- a/linux/syscallent.h
-+++ b/linux/syscallent.h
-@@ -357,12 +357,12 @@
- { 6, TF, sys_fallocate, "fallocate" }, /* 324 */
- { 4, TD, sys_timerfd_settime, "timerfd_settime"}, /* 325 */
- { 2, TD, sys_timerfd_gettime, "timerfd_gettime"}, /* 326 */
-- { 5, 0, printargs, "SYS_327" }, /* 327 */
-- { 5, 0, printargs, "SYS_328" }, /* 328 */
-- { 5, 0, printargs, "SYS_329" }, /* 329 */
-- { 5, 0, printargs, "SYS_330" }, /* 330 */
-- { 5, 0, printargs, "SYS_331" }, /* 331 */
-- { 5, 0, printargs, "SYS_332" }, /* 332 */
-+ { 4, TD|TS, sys_signalfd4, "signalfd4" }, /* 327 */
-+ { 2, TD, sys_eventfd2, "eventfd2" }, /* 328 */
-+ { 1, 0, sys_epoll_create1, "epoll_create1" }, /* 329 */
-+ { 3, TD, sys_dup3, "dup3" }, /* 330 */
-+ { 2, TD, sys_pipe2, "pipe2" }, /* 331 */
-+ { 1, TD, printargs, "inotify_init1" }, /* 332 */
- { 5, 0, printargs, "SYS_333" }, /* 333 */
- { 5, 0, printargs, "SYS_334" }, /* 334 */
- { 5, 0, printargs, "SYS_335" }, /* 335 */
-diff --git a/linux/x86_64/syscallent.h b/linux/x86_64/syscallent.h
-index 0b2150b..4b4eaf0 100644
---- a/linux/x86_64/syscallent.h
-+++ b/linux/x86_64/syscallent.h
-@@ -286,3 +286,10 @@
- { 6, TF, sys_fallocate, "fallocate" }, /* 285 */
- { 4, TD, sys_timerfd_settime, "timerfd_settime"}, /* 286 */
- { 2, TD, sys_timerfd_gettime, "timerfd_gettime"}, /* 287 */
-+ { 6, TN, printargs, "paccept" }, /* 288 */
-+ { 4, TD|TS, sys_signalfd4, "signalfd4" }, /* 289 */
-+ { 2, TD, sys_eventfd2, "eventfd2" }, /* 290 */
-+ { 1, 0, sys_epoll_create1, "epoll_create1" }, /* 291 */
-+ { 3, TD, sys_dup3, "dup3" }, /* 292 */
-+ { 2, TD, sys_pipe2, "pipe2" }, /* 293 */
-+ { 1, TD, printargs, "inotify_init1" }, /* 294 */
-diff --git a/net.c b/net.c
-index f5426b2..d5426bd 100644
---- a/net.c
-+++ b/net.c
-@@ -1463,31 +1463,50 @@
- return sys_accept(tcp);
- }
-
--int
--sys_pipe(tcp)
--struct tcb *tcp;
--{
--
--#if defined(LINUX) && !defined(SPARC) && !defined(SPARC64) && !defined(SH) && !defined(IA64)
-- int fds[2];
-+extern const struct xlat open_mode_flags[];
-
-+ static int
-+do_pipe(struct tcb *tcp, int flags_arg)
-+{
- if (exiting(tcp)) {
- if (syserror(tcp)) {
- tprintf("%#lx", tcp->u_arg[0]);
-- return 0;
-- }
-- if (umoven(tcp, tcp->u_arg[0], sizeof fds, (char *) fds) < 0)
-- tprintf("[...]");
-- else
-- tprintf("[%u, %u]", fds[0], fds[1]);
-- }
-+ } else {
-+#if defined(LINUX) && !defined(SPARC) && !defined(SPARC64) && !defined(SH) && !defined(IA64)
-+ int fds[2];
-+
-+ if (umoven(tcp, tcp->u_arg[0], sizeof fds, (char *) fds) < 0)
-+ tprintf("[...]");
-+ else
-+ tprintf("[%u, %u]", fds[0], fds[1]);
- #elif defined(SPARC) || defined(SPARC64) || defined(SH) || defined(SVR4) || defined(FREEBSD) || defined(IA64)
-- if (exiting(tcp))
-- tprintf("[%lu, %lu]", tcp->u_rval, getrval2(tcp));
-+ tprintf("[%lu, %lu]", tcp->u_rval, getrval2(tcp));
-+#else
-+ tprintf("%#lx", tcp->u_arg[0]);
- #endif
-+ }
-+ if (flags_arg >= 0) {
-+ tprintf(", ");
-+ printflags(open_mode_flags, tcp->u_arg[flags_arg], "O_???");
-+ }
-+ }
- return 0;
- }
-
-+ int
-+sys_pipe(struct tcb *tcp)
-+{
-+ return do_pipe(tcp, -1);
-+}
-+
-+#ifdef LINUX
-+ int
-+sys_pipe2(struct tcb *tcp)
-+{
-+ return do_pipe(tcp, 1);
-+}
-+#endif
-+
- int
- sys_socketpair(tcp)
- struct tcb *tcp;
-diff --git a/signal.c b/signal.c
-index 12bbac3..0366bb5 100644
---- a/signal.c
-+++ b/signal.c
-@@ -2011,15 +2011,32 @@ struct tcb *tcp;
- return 0;
- }
-
--int
--sys_signalfd(tcp)
--struct tcb *tcp;
-+extern const struct xlat open_mode_flags[];
-+
-+static int
-+do_signalfd(struct tcb *tcp, int flags_arg)
- {
- if (entering(tcp)) {
- tprintf("%ld, ", tcp->u_arg[0]);
- print_sigset(tcp, tcp->u_arg[1], 1);
- tprintf("%lu", tcp->u_arg[2]);
-+ if (flags_arg >= 0) {
-+ tprintf(", ");
-+ printflags(open_mode_flags, tcp->u_arg[flags_arg], "O_???");
-+ }
- }
- return 0;
- }
-+
-+int
-+sys_signalfd(struct tcb *tcp)
-+{
-+ return do_signalfd(tcp, -1);
-+}
-+
-+int
-+sys_signalfd4(struct tcb *tcp)
-+{
-+ return do_signalfd(tcp, 3);
-+}
- #endif /* LINUX */
-commit feeceab4c8bfde6542d78048854c3bdc7ea9c99b
-Author: ldv <ldv>
-Date: Mon Nov 10 17:21:23 2008 +0000
-
- 2008-10-22 Dmitry V. Levin <ldv@altlinux.org>
-
- Handle socket type flags introduced in linux 2.6.27.
- * net.c (socktypes): Add SOCK_DCCP.
- (sock_type_flags): New xlat structure.
- (tprint_sock_type): New function.
- (sys_socket, sys_socketpair): Use it to parse socket type and
- socket type flags.
-
-diff --git a/net.c b/net.c
-index c302b1f..f5426b2 100644
---- a/net.c
-+++ b/net.c
-@@ -27,7 +27,7 @@
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
-- * $Id$
-+ * $Id$
- */
-
- #include "defs.h"
-@@ -320,17 +320,32 @@ static const struct xlat socktypes[] = {
- #ifdef SOCK_RAW
- { SOCK_RAW, "SOCK_RAW" },
- #endif
-+#ifdef SOCK_RDM
-+ { SOCK_RDM, "SOCK_RDM" },
-+#endif
- #ifdef SOCK_SEQPACKET
- { SOCK_SEQPACKET,"SOCK_SEQPACKET"},
- #endif
--#ifdef SOCK_RDM
-- { SOCK_RDM, "SOCK_RDM" },
-+#ifdef SOCK_DCCP
-+ { SOCK_DCCP, "SOCK_DCCP" },
- #endif
- #ifdef SOCK_PACKET
- { SOCK_PACKET, "SOCK_PACKET" },
- #endif
- { 0, NULL },
- };
-+const struct xlat sock_type_flags[] = {
-+#ifdef SOCK_CLOEXEC
-+ { SOCK_CLOEXEC, "SOCK_CLOEXEC" },
-+#endif
-+#ifdef SOCK_NONBLOCK
-+ { SOCK_NONBLOCK,"SOCK_NONBLOCK" },
-+#endif
-+ { 0, NULL },
-+};
-+#ifndef SOCK_TYPE_MASK
-+# define SOCK_TYPE_MASK 0xf
-+#endif
- static const struct xlat socketlayers[] = {
- #if defined(SOL_IP)
- { SOL_IP, "SOL_IP" },
-@@ -1182,14 +1197,33 @@ long addr;
-
- #endif /* HAVE_SENDMSG */
-
-+/*
-+ * low bits of the socket type define real socket type,
-+ * other bits are socket type flags.
-+ */
-+static void
-+tprint_sock_type(struct tcb *tcp, int flags)
-+{
-+ const char *str = xlookup(socktypes, flags & SOCK_TYPE_MASK);
-+
-+ if (str)
-+ {
-+ tprintf("%s", str);
-+ flags &= ~SOCK_TYPE_MASK;
-+ if (!flags)
-+ return;
-+ tprintf("|");
-+ }
-+ printflags(sock_type_flags, flags, "SOCK_???");
-+}
-+
- int
--sys_socket(tcp)
--struct tcb *tcp;
-+sys_socket(struct tcb *tcp)
- {
- if (entering(tcp)) {
- printxval(domains, tcp->u_arg[0], "PF_???");
- tprintf(", ");
-- printxval(socktypes, tcp->u_arg[1], "SOCK_???");
-+ tprint_sock_type(tcp, tcp->u_arg[1]);
- tprintf(", ");
- switch (tcp->u_arg[0]) {
- case PF_INET:
-@@ -1489,8 +1523,7 @@ struct tcb *tcp;
- }
-
- int
--sys_socketpair(tcp)
--struct tcb *tcp;
-+sys_socketpair(struct tcb *tcp)
- {
- #ifdef LINUX
- int fds[2];
-@@ -1499,7 +1532,7 @@ struct tcb *tcp;
- if (entering(tcp)) {
- printxval(domains, tcp->u_arg[0], "PF_???");
- tprintf(", ");
-- printxval(socktypes, tcp->u_arg[1], "SOCK_???");
-+ tprint_sock_type(tcp, tcp->u_arg[1]);
- tprintf(", ");
- switch (tcp->u_arg[0]) {
- case PF_INET:
+++ /dev/null
---- strace-4.5.18/ipc.c.orig 2007-01-15 21:25:52.000000000 +0100
-+++ strace-4.5.18/ipc.c 2009-10-07 22:11:24.392613451 +0200
-@@ -152,6 +152,12 @@
- { 0, NULL },
- };
-
-+static const struct xlat semop_flags[] = {
-+ { SEM_UNDO, "SEM_UNDO" },
-+ { IPC_NOWAIT, "IPC_NOWAIT" },
-+ { 0, NULL },
-+};
-+
- int sys_msgget(tcp)
- struct tcb *tcp;
- {
-@@ -273,14 +279,40 @@
- int sys_semop(tcp)
- struct tcb *tcp;
- {
-+ int i;
-+
- if (entering(tcp)) {
- tprintf("%lu", tcp->u_arg[0]);
- if (indirect_ipccall(tcp)) {
-- tprintf(", %#lx", tcp->u_arg[3]);
-- tprintf(", %lu", tcp->u_arg[1]);
-+ tprintf(", %#lx {", tcp->u_arg[3]);
-+ for(i = 0; i < tcp->u_arg[1]; i++) {
-+ struct sembuf sb;
-+ if(i != 0)
-+ tprintf(", ");
-+ if (umove(tcp, tcp->u_arg[3]+i*sizeof(struct sembuf), &sb) < 0)
-+ tprintf("{???}");
-+ else {
-+ tprintf("{%u, %d, ", sb.sem_num, sb.sem_op);
-+ printflags(semop_flags, sb.sem_flg, "SEM_???");
-+ tprintf("}");
-+ }
-+ }
-+ tprintf("}, %lu", tcp->u_arg[1]);
- } else {
-- tprintf(", %#lx", tcp->u_arg[1]);
-- tprintf(", %lu", tcp->u_arg[2]);
-+ tprintf(", %#lx {", tcp->u_arg[1]);
-+ for(i = 0; i < tcp->u_arg[2]; i++) {
-+ struct sembuf sb;
-+ if(i != 0)
-+ tprintf(", ");
-+ if(umove(tcp, tcp->u_arg[1]+i*sizeof(struct sembuf), &sb) < 0)
-+ tprintf("{???}");
-+ else {
-+ tprintf("{%u, %d, ", sb.sem_num, sb.sem_op);
-+ printflags(semop_flags, sb.sem_flg, "SEM_???");
-+ tprintf("}");
-+ }
-+ }
-+ tprintf("}, %lu", tcp->u_arg[2]);
- }
- }
- return 0;
-@@ -290,15 +322,41 @@
- int sys_semtimedop(tcp)
- struct tcb *tcp;
- {
-+ int i;
-+
- if (entering(tcp)) {
- tprintf("%lu", tcp->u_arg[0]);
- if (indirect_ipccall(tcp)) {
-- tprintf(", %#lx", tcp->u_arg[3]);
-- tprintf(", %lu, ", tcp->u_arg[1]);
-+ tprintf(", %#lx {", tcp->u_arg[3]);
-+ for(i = 0; i < tcp->u_arg[1]; i++) {
-+ struct sembuf sb;
-+ if(i != 0)
-+ tprintf(", ");
-+ if(umove(tcp, tcp->u_arg[3]+i*sizeof(struct sembuf), &sb) < 0)
-+ tprintf("{???}");
-+ else {
-+ tprintf("{%u, %d, ", sb.sem_num, sb.sem_op);
-+ printflags(semop_flags, sb.sem_flg, "SEM_???");
-+ tprintf("}");
-+ }
-+ }
-+ tprintf("}, %lu, ", tcp->u_arg[1]);
- printtv(tcp, tcp->u_arg[5]);
- } else {
-- tprintf(", %#lx", tcp->u_arg[1]);
-- tprintf(", %lu, ", tcp->u_arg[2]);
-+ tprintf(", %#lx {", tcp->u_arg[1]);
-+ for(i = 0; i < tcp->u_arg[2]; i++) {
-+ struct sembuf sb;
-+ if(i != 0)
-+ tprintf(", ");
-+ if(umove(tcp, tcp->u_arg[1]+i*sizeof(struct sembuf), &sb) < 0)
-+ tprintf("{???}");
-+ else {
-+ tprintf("{%u, %d, ", sb.sem_num, sb.sem_op);
-+ printflags(semop_flags, sb.sem_flg, "SEM_???");
-+ tprintf("}");
-+ }
-+ }
-+ tprintf("}, %lu, ", tcp->u_arg[2]);
- printtv(tcp, tcp->u_arg[3]);
- }
- }
+++ /dev/null
---- util.c
-+++ util.c
-@@ -407,6 +407,12 @@ unsigned long uid;
-
- static char path[MAXPATHLEN + 1];
-
-+/*
-+ * Quote string `instr' of length `size'
-+ * Write up to (3 + `size' * 4) bytes to `outstr' buffer.
-+ * If `len' < 0, treat `instr' as a NUL-terminated string
-+ * and quote at most (`size' - 1) bytes.
-+ */
- static int
- string_quote(const char *instr, char *outstr, int len, int size)
- {
-@@ -417,12 +423,18 @@ string_quote(const char *instr, char *outstr, int len, int size)
- if (xflag > 1)
- usehex = 1;
- else if (xflag) {
-+ /* Check for presence of symbol which require
-+ to hex-quote the whole string. */
- for (i = 0; i < size; ++i) {
- c = ustr[i];
-- if (len < 0 && i == size - 2 && c != '\0')
-- ++i;
-- if (len < 0 && c == '\0')
-- break;
-+ /* Check for NUL-terminated string. */
-+ if (len < 0) {
-+ if (c == '\0')
-+ break;
-+ /* Quote at most size - 1 bytes. */
-+ if (i == size - 1)
-+ continue;
-+ }
- if (!isprint(c) && !isspace(c)) {
- usehex = 1;
- break;
-@@ -433,20 +445,31 @@ string_quote(const char *instr, char *outstr, int len, int size)
- *s++ = '\"';
-
- if (usehex) {
-+ /* Hex-quote the whole string. */
- for (i = 0; i < size; ++i) {
- c = ustr[i];
-- if (len < 0 && c == '\0')
-- break;
-+ /* Check for NUL-terminated string. */
-+ if (len < 0) {
-+ if (c == '\0')
-+ break;
-+ /* Quote at most size - 1 bytes. */
-+ if (i == size - 1)
-+ continue;
-+ }
- sprintf(s, "\\x%02x", c);
- s += 4;
- }
- } else {
- for (i = 0; i < size; ++i) {
- c = ustr[i];
-- if (len < 0 && i == size - 2 && c != '\0')
-- ++i;
-- if (len < 0 && c == '\0')
-- break;
-+ /* Check for NUL-terminated string. */
-+ if (len < 0) {
-+ if (c == '\0')
-+ break;
-+ /* Quote at most size - 1 bytes. */
-+ if (i == size - 1)
-+ continue;
-+ }
- switch (c) {
- case '\"': case '\\':
- *s++ = '\\';
-@@ -495,18 +518,25 @@ string_quote(const char *instr, char *outstr, int len, int size)
- return i == size;
- }
-
-+/*
-+ * Print path string specified by address `addr' and length `n'.
-+ * If path length exceeds `n', append `...' to the output.
-+ */
- void
- printpathn(struct tcb *tcp, long addr, int n)
- {
-- if (n > sizeof path - 1)
-- n = sizeof path - 1;
--
-- if (addr == 0) {
-+ if (!addr) {
- tprintf("NULL");
- return;
- }
-
-+ /* Cap path length to the path buffer size,
-+ and NUL-terminate the buffer. */
-+ if (n > sizeof path - 1)
-+ n = sizeof path - 1;
- path[n] = '\0';
-+
-+ /* Fetch one byte more to find out whether path length > n. */
- if (umovestr(tcp, addr, n + 1, path) < 0)
- tprintf("%#lx", addr);
- else {
-@@ -515,7 +545,8 @@ printpathn(struct tcb *tcp, long addr, int n)
-
- if (trunc)
- path[n] = '\0';
-- if (string_quote(path, outstr, -1, n + 1) || trunc)
-+ (void) string_quote(path, outstr, -1, n + 1);
-+ if (trunc)
- strcat(outstr, "...");
- tprintf("%s", outstr);
- }
-@@ -527,6 +558,11 @@ printpath(struct tcb *tcp, long addr)
- printpathn(tcp, addr, sizeof path - 1);
- }
-
-+/*
-+ * Print string specified by address `addr' and length `len'.
-+ * If `len' < 0, treat the string as a NUL-terminated string.
-+ * If string length exceeds `max_strlen', append `...' to the output.
-+ */
- void
- printstr(struct tcb *tcp, long addr, int len)
- {
-@@ -538,32 +574,39 @@ printstr(struct tcb *tcp, long addr, int len)
- tprintf("NULL");
- return;
- }
-- if (!str) {
-- if ((str = malloc(max_strlen + 1)) == NULL
-- || (outstr = malloc(4*max_strlen
-- + sizeof "\"\"...")) == NULL) {
-- fprintf(stderr, "out of memory\n");
-- tprintf("%#lx", addr);
-- return;
-- }
-+ /* Allocate static buffers if they are not allocated yet. */
-+ if (!str)
-+ str = malloc(max_strlen + 1);
-+ if (!outstr)
-+ outstr = malloc(4 * max_strlen + sizeof "\"...\"");
-+ if (!str || !outstr) {
-+ fprintf(stderr, "out of memory\n");
-+ tprintf("%#lx", addr);
-+ return;
- }
-
- if (len < 0) {
-+ /*
-+ * Treat as a NUL-terminated string: fetch one byte more
-+ * because string_quote() quotes one byte less.
-+ */
- size = max_strlen + 1;
-+ str[max_strlen] = '\0';
- if (umovestr(tcp, addr, size, str) < 0) {
- tprintf("%#lx", addr);
- return;
- }
- }
- else {
-- size = MIN(len, max_strlen + 1);
-+ size = MIN(len, max_strlen);
- if (umoven(tcp, addr, size, str) < 0) {
- tprintf("%#lx", addr);
- return;
- }
- }
-
-- if (string_quote(str, outstr, len, size))
-+ if (string_quote(str, outstr, len, size) &&
-+ (len < 0 || len > max_strlen))
- strcat(outstr, "...");
-
- tprintf("%s", outstr);
-