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>
This commit is contained in:
Denys Vlasenko 2013-02-22 14:47:39 +01:00
parent 9cbc15b7e7
commit 763258071c

78
util.c
View File

@ -661,54 +661,70 @@ dumpstr(struct tcb *tcp, long addr, int len)
{
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++ = ' ';
}
}
*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++ = ' ';
*dst++ = ' ';
}
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);
}
}