Fix a bug in dumpstr (no null termination). Essentially rewrote dumpstr
This is a 14 year old bug (!).
It wasn't biting us merely because outstr[80] was static, thus ended up
in bss and whatever was after it "accidentally" provided the NUL byte.
When dumpstr was changed to use on-stack buffer, the bug reared its ugly head.
This is a rewrite which is smaller and should be significantly faster
for _long_ strings.
text data bss dec hex filename
244627 680 10860 256167 3e8a7 strace.t9/strace
244563 680 10860 256103 3e867 strace.ta/strace
* util.c (dumpstr): Rewrite to be faster and smaller.
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
diff --git a/util.c b/util.c
index 4c22c5f..b398625 100644
--- a/util.c
+++ b/util.c
@@ -661,54 +661,70 @@
{
static int strsize = -1;
static unsigned char *str;
- char *s;
- int i, j;
- if (strsize < len) {
+ char outbuf[
+ (
+ (sizeof(
+ "xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx "
+ "1234567890123456") + /*in case I'm off by few:*/ 4)
+ /*align to 8 to make memset easier:*/ + 7) & -8
+ ];
+ const unsigned char *src;
+ int i;
+
+ memset(outbuf, ' ', sizeof(outbuf));
+
+ if (strsize < len + 16) {
free(str);
- str = malloc(len);
+ str = malloc(len + 16);
if (!str) {
strsize = -1;
fprintf(stderr, "Out of memory\n");
return;
}
- strsize = len;
+ strsize = len + 16;
}
if (umoven(tcp, addr, len, (char *) str) < 0)
return;
- for (i = 0; i < len; i += 16) {
- char outstr[80];
+ /* Space-pad to 16 bytes */
+ i = len;
+ while (i & 0xf)
+ str[i++] = ' ';
- s = outstr;
- sprintf(s, " | %05x ", i);
- s += 9;
- for (j = 0; j < 16; j++) {
- if (j == 8)
- *s++ = ' ';
- if (i + j < len) {
- sprintf(s, " %02x", str[i + j]);
- s += 3;
+ i = 0;
+ src = str;
+ while (i < len) {
+ char *dst = outbuf;
+ /* Hex dump */
+ do {
+ if (i < len) {
+ *dst++ = "0123456789abcdef"[*src >> 4];
+ *dst++ = "0123456789abcdef"[*src & 0xf];
}
else {
- *s++ = ' '; *s++ = ' '; *s++ = ' ';
+ *dst++ = ' ';
+ *dst++ = ' ';
}
- }
- *s++ = ' '; *s++ = ' ';
- for (j = 0; j < 16; j++) {
- if (j == 8)
- *s++ = ' ';
- if (i + j < len) {
- if (isprint(str[i + j]))
- *s++ = str[i + j];
- else
- *s++ = '.';
- }
+ dst++; /* space is there by memset */
+ i++;
+ if ((i & 7) == 0)
+ dst++; /* space is there by memset */
+ src++;
+ } while (i & 0xf);
+ /* ASCII dump */
+ i -= 16;
+ src -= 16;
+ do {
+ if (*src >= ' ' && *src < 0x7f)
+ *dst++ = *src;
else
- *s++ = ' ';
- }
- tprintf("%s |\n", outstr);
+ *dst++ = '.';
+ src++;
+ } while (++i & 0xf);
+ *dst = '\0';
+ tprintf(" | %05x %s |\n", i, outbuf);
}
}