FreeCalypso > hg > freecalypso-sw
changeset 858:4c6e7ada647b
compressed trace decoder almost fully implemented
author | Space Falcon <falcon@ivan.Harhan.ORG> |
---|---|
date | Sat, 02 May 2015 08:08:26 +0000 |
parents | 2768b4339275 |
children | d32dff865575 |
files | rvinterf/ctracedec/decode.c rvinterf/ctracedec/doprnt.c rvinterf/ctracedec/processlog.c rvinterf/ctracedec/readtab.c |
diffstat | 4 files changed, 696 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rvinterf/ctracedec/decode.c Sat May 02 08:08:26 2015 +0000 @@ -0,0 +1,150 @@ +/* + * This module implements the actual decoding of compressed traces. + */ + +#include <sys/types.h> +#include <stdio.h> +#include <ctype.h> +#include <string.h> +#include <strings.h> +#include <stdlib.h> + +extern char *str2ind_tab_filename; +extern int str2ind_array_size; +extern char **str2ind_orig_strings; +extern char **str2ind_param_strings; + +#define MAX_PRINTF_PARAMS 16 + +static int cindex, cindex_nchars; +static u_char param_bytes_array[256]; +static int param_bytes_count; +static char *format_string, *param_type_string; +static int num_printf_params; +static u_long printf_params[MAX_PRINTF_PARAMS]; +static char output_buf[2048]; + +decode_hex_digit(c) +{ + if (isdigit(c)) + return(c - '0'); + else if (isupper(c)) + return(c - 'A' + 10); + else + return(c - 'a' + 10); +} + +static int +decode_idx_and_params(line) + char *line; +{ + char *cp; + u_char *dp; + + for (cp = line; isdigit(*cp); cp++) + ; + if (*cp && *cp != ' ') + return(-1); + cindex = atoi(line); + cindex_nchars = cp - line; + for (dp = param_bytes_array; *cp; ) { + if (*cp++ != ' ') + return(-1); + if (!isxdigit(cp[0]) || !isxdigit(cp[1])) + return(-1); + *dp++ = decode_hex_digit(cp[0]) << 4 | decode_hex_digit(cp[1]); + cp += 2; + } + param_bytes_count = dp - param_bytes_array; + return(0); +} + +static void +decode_parameters(filename_for_errs, lineno_for_errs) + char *filename_for_errs; +{ + int pi, type; + u_char *bp, *endp; + + bp = param_bytes_array; + endp = bp + param_bytes_count; + for (pi = 0; pi < num_printf_params; pi++) { + type = param_type_string[pi]; + switch (type) { + case 'c': + if (bp >= endp) { +wrong_param_byte_count: fprintf(stderr, + "%s line %d: wrong number of parameter bytes for %s entry #%d\n", + filename_for_errs, lineno_for_errs, + str2ind_tab_filename, cindex); + exit(1); + } + printf_params[pi] = *bp++; + continue; + case 'i': + case 'p': + case '*': + if (bp > endp - 4) + goto wrong_param_byte_count; + printf_params[pi] = (u_long) bp[0] | + (u_long) bp[1] << 8 | + (u_long) bp[2] << 16 | + (u_long) bp[3] << 24; + bp += 4; + continue; + case 's': + printf_params[pi] = (u_long) bp; + for (;;) { + if (bp >= endp) { + fprintf(stderr, + "%s line %d: unterminated string parameter in compressed trace\n", + filename_for_errs, + lineno_for_errs); + exit(1); + } + if (!*bp++) + break; + } + continue; + default: + fprintf(stderr, + "%s entry #%d: parameter type \'%c\' not supported\n", + str2ind_tab_filename, cindex, type); + exit(1); + } + } + if (bp != endp) + goto wrong_param_byte_count; +} + +process_ctrace_line(line, cindex_offset, filename_for_errs, lineno_for_errs) + char *line, *filename_for_errs; +{ + if (decode_idx_and_params(line + cindex_offset) < 0) { + fprintf(stderr, + "%s line %d: unable to decode compressed trace line\n", + filename_for_errs, lineno_for_errs); + exit(1); + } + if (cindex >= str2ind_array_size) { + fprintf(stderr, + "%s line %d: index %d exceeds the range of %s\n", + filename_for_errs, lineno_for_errs, cindex, + str2ind_tab_filename); + exit(1); + } + format_string = str2ind_orig_strings[cindex]; + param_type_string = str2ind_param_strings[cindex]; + num_printf_params = strlen(param_type_string); + if (num_printf_params > MAX_PRINTF_PARAMS) { + fprintf(stderr, + "error: entry #%d in %s has too many parameters\n", + cindex, str2ind_tab_filename); + exit(1); + } + decode_parameters(filename_for_errs, lineno_for_errs); + ind2str_doprnt(format_string, printf_params, output_buf); + printf("%.*s \"%s\"\n", cindex_offset + cindex_nchars, line, + output_buf); + return(0); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rvinterf/ctracedec/doprnt.c Sat May 02 08:08:26 2015 +0000 @@ -0,0 +1,320 @@ +/* + * We need our own implementation of an sprintf-like function in order + * to expand compressed traces with format strings from str2ind.tab + * and parameters decoded from the serial byte stream. This module is + * a hacked-up version of the guts of the printf family of functions + * from 4.3BSD-Tahoe. + */ + +#include <sys/types.h> +#include <ctype.h> + +static void +safe_out_char(c, pp) + int c; + char **pp; +{ + char *dp; + + c &= 0xFF; + dp = *pp; + if (c & 0x80) { + *dp++ = 'M'; + *dp++ = '-'; + c &= 0x7F; + } + if (c < 0x20) { + *dp++ = '^'; + *dp++ = c + '@'; + } else if (c == 0x7F) { + *dp++ = '^'; + *dp++ = '?'; + } else + *dp++ = c; + *pp = dp; +} + +#define PUTC(ch) safe_out_char((ch), &outp) + +#define ARG() \ + _ulong = *argp++; + +#define BUF 12 + +#define todigit(c) ((c) - '0') +#define tochar(n) ((n) + '0') + +#define LONGINT 0x01 /* long integer */ +#define LONGDBL 0x02 /* long double; unimplemented */ +#define SHORTINT 0x04 /* short integer */ +#define ALT 0x08 /* alternate form */ +#define LADJUST 0x10 /* left adjustment */ +#define ZEROPAD 0x20 /* zero (as opposed to blank) pad */ +#define HEXPREFIX 0x40 /* add 0x or 0X prefix */ + +ind2str_doprnt(fmt0, argp, outp) + u_char *fmt0, *outp; + u_long *argp; +{ + register u_char *fmt; /* format string */ + register int ch; /* character from fmt */ + register int cnt; /* return value accumulator */ + register int n; /* random handy integer */ + register char *t; /* buffer pointer */ + u_long _ulong; /* integer arguments %[diouxX] */ + int base; /* base for [diouxX] conversion */ + int dprec; /* decimal precision in [diouxX] */ + int fieldsz; /* field size expanded by sign, etc */ + int flags; /* flags as above */ + int prec; /* precision from format (%.3d), or -1 */ + int realsz; /* field size expanded by decimal precision */ + int size; /* size of converted field or string */ + int width; /* width from format (%8d), or 0 */ + char sign; /* sign prefix (' ', '+', '-', or \0) */ + char softsign; /* temporary negative sign for floats */ + char *digs; /* digits for [diouxX] conversion */ + char buf[BUF]; /* space for %c, %[diouxX], %[eEfgG] */ + + fmt = fmt0; + digs = "0123456789abcdef"; + for (cnt = 0;; ++fmt) { + for (; (ch = *fmt) && ch != '%'; ++cnt, ++fmt) + PUTC(ch); + if (!ch) { + *outp = '\0'; + return (cnt); + } + + flags = 0; dprec = 0; width = 0; + prec = -1; + sign = '\0'; + +rflag: switch (*++fmt) { + case ' ': + /* + * ``If the space and + flags both appear, the space + * flag will be ignored.'' + * -- ANSI X3J11 + */ + if (!sign) + sign = ' '; + goto rflag; + case '#': + flags |= ALT; + goto rflag; + case '*': + /* + * ``A negative field width argument is taken as a + * - flag followed by a positive field width.'' + * -- ANSI X3J11 + * They don't exclude field widths read from args. + */ + if ((width = *argp++) >= 0) + goto rflag; + width = -width; + /* FALLTHROUGH */ + case '-': + flags |= LADJUST; + goto rflag; + case '+': + sign = '+'; + goto rflag; + case '.': + if (*++fmt == '*') + n = *argp++; + else { + n = 0; + while (isascii(*fmt) && isdigit(*fmt)) + n = 10 * n + todigit(*fmt++); + --fmt; + } + prec = n < 0 ? -1 : n; + goto rflag; + case '0': + /* + * ``Note that 0 is taken as a flag, not as the + * beginning of a field width.'' + * -- ANSI X3J11 + */ + flags |= ZEROPAD; + goto rflag; + case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + n = 0; + do { + n = 10 * n + todigit(*fmt); + } while (isascii(*++fmt) && isdigit(*fmt)); + width = n; + --fmt; + goto rflag; + case 'L': + flags |= LONGDBL; + goto rflag; + case 'h': + flags |= SHORTINT; + goto rflag; + case 'l': + flags |= LONGINT; + goto rflag; + case 'c': + *(t = buf) = *argp++; + size = 1; + sign = '\0'; + goto pforw; + case 'D': + flags |= LONGINT; + /*FALLTHROUGH*/ + case 'd': + case 'i': + ARG(); + if ((long)_ulong < 0) { + _ulong = -_ulong; + sign = '-'; + } + base = 10; + goto number; + case 'O': + flags |= LONGINT; + /*FALLTHROUGH*/ + case 'o': + ARG(); + base = 8; + goto nosign; + case 'p': + /* + * ``The argument shall be a pointer to void. The + * value of the pointer is converted to a sequence + * of printable characters, in an implementation- + * defined manner.'' + * -- ANSI X3J11 + */ + /* NOSTRICT */ + _ulong = *argp++; + base = 16; + goto nosign; + case 's': + if (!(t = (char *)*argp++)) + t = "(null)"; + if (prec >= 0) { + /* + * can't use strlen; can only look for the + * NUL in the first `prec' characters, and + * strlen() will go further. + */ + char *p; + + for (p = t, size = 0; size < prec; p++, size++) + if (*p == '\0') + break; + } else + size = strlen(t); + sign = '\0'; + goto pforw; + case 'U': + flags |= LONGINT; + /*FALLTHROUGH*/ + case 'u': + ARG(); + base = 10; + goto nosign; + case 'X': + digs = "0123456789ABCDEF"; + /* FALLTHROUGH */ + case 'x': + ARG(); + base = 16; + /* leading 0x/X only if non-zero */ + if (flags & ALT && _ulong != 0) + flags |= HEXPREFIX; + + /* unsigned conversions */ +nosign: sign = '\0'; + /* + * ``... diouXx conversions ... if a precision is + * specified, the 0 flag will be ignored.'' + * -- ANSI X3J11 + */ +number: if ((dprec = prec) >= 0) + flags &= ~ZEROPAD; + + /* + * ``The result of converting a zero value with an + * explicit precision of zero is no characters.'' + * -- ANSI X3J11 + */ + t = buf + BUF; + if (_ulong != 0 || prec != 0) { + do { + *--t = digs[_ulong % base]; + _ulong /= base; + } while (_ulong); + digs = "0123456789abcdef"; + if (flags & ALT && base == 8 && *t != '0') + *--t = '0'; /* octal leading 0 */ + } + size = buf + BUF - t; + +pforw: + /* + * All reasonable formats wind up here. At this point, + * `t' points to a string which (if not flags&LADJUST) + * should be padded out to `width' places. If + * flags&ZEROPAD, it should first be prefixed by any + * sign or other prefix; otherwise, it should be blank + * padded before the prefix is emitted. After any + * left-hand padding and prefixing, emit zeroes + * required by a decimal [diouxX] precision, then print + * the string proper, then emit zeroes required by any + * leftover floating precision; finally, if LADJUST, + * pad with blanks. + */ + + /* + * compute actual size, so we know how much to pad + * fieldsz excludes decimal prec; realsz includes it + */ + fieldsz = size; + if (sign) + fieldsz++; + if (flags & HEXPREFIX) + fieldsz += 2; + realsz = dprec > fieldsz ? dprec : fieldsz; + + /* right-adjusting blank padding */ + if ((flags & (LADJUST|ZEROPAD)) == 0 && width) + for (n = realsz; n < width; n++) + PUTC(' '); + /* prefix */ + if (sign) + PUTC(sign); + if (flags & HEXPREFIX) { + PUTC('0'); + PUTC((char)*fmt); + } + /* right-adjusting zero padding */ + if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD) + for (n = realsz; n < width; n++) + PUTC('0'); + /* leading zeroes from decimal precision */ + for (n = fieldsz; n < dprec; n++) + PUTC('0'); + + for (n = size; --n >= 0; ) + PUTC(*t++); + /* left-adjusting padding (always blank) */ + if (flags & LADJUST) + for (n = realsz; n < width; n++) + PUTC(' '); + /* finally, adjust cnt */ + cnt += width > realsz ? width : realsz; + break; + case '\0': /* "%?" prints ?, unless ? is NULL */ + *outp = '\0'; + return (cnt); + default: + PUTC((char)*fmt); + cnt++; + } + } + /* NOTREACHED */ +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rvinterf/ctracedec/processlog.c Sat May 02 08:08:26 2015 +0000 @@ -0,0 +1,81 @@ +/* + * This module contains the code that processes rvtdump/rvinterf log files + * at the high level and identifies which lines are compressed traces. + */ + +#include <stdio.h> +#include <ctype.h> +#include <string.h> +#include <strings.h> +#include <stdlib.h> + +is_logline_ctrace(line) + char *line; +{ + char *cp = line; + + if (*cp++ != '[') + return(0); + if (!isdigit(*cp++)) + return(0); + if (!isdigit(*cp++)) + return(0); + if (*cp++ != ':') + return(0); + if (!isdigit(*cp++)) + return(0); + if (!isdigit(*cp++)) + return(0); + if (*cp++ != ':') + return(0); + if (!isdigit(*cp++)) + return(0); + if (!isdigit(*cp++)) + return(0); + if (strncmp(cp, "] GPF trace ", 12)) + return(0); + cp += 12; + while (isalpha(*cp)) { + while (*cp && !isspace(*cp)) + cp++; + if (isspace(*cp)) + cp++; + else + return(0); + } + if (isdigit(*cp)) + return(cp - line); + else + return(0); +} + +process_log_file(filename) + char *filename; +{ + FILE *f; + char linebuf[512], *cp; + int lineno, i; + + f = fopen(filename, "r"); + if (!f) { + perror(filename); + exit(1); + } + for (lineno = 1; fgets(linebuf, sizeof linebuf, f); lineno++) { + cp = index(linebuf, '\n'); + if (!cp) { + fprintf(stderr, + "error: %s line %d is too long or unterminated\n", + filename, lineno); + exit(1); + } + *cp = '\0'; + i = is_logline_ctrace(linebuf); + if (i) + process_ctrace_line(linebuf, i, filename, lineno); + else + puts(linebuf); + } + fclose(f); + return(0); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rvinterf/ctracedec/readtab.c Sat May 02 08:08:26 2015 +0000 @@ -0,0 +1,145 @@ +/* + * This module handles the reading and parsing of str2ind.tab + */ + +#include <stdio.h> +#include <ctype.h> +#include <string.h> +#include <strings.h> +#include <stdlib.h> + +extern char *str2ind_tab_filename; + +int str2ind_array_size; +char **str2ind_orig_strings; +char **str2ind_param_strings; + +static FILE *readF; +static char linebuf[256]; +static int lineno; + +static void +read_line() +{ + char *cp; + + if (!fgets(linebuf, sizeof linebuf, readF)) { + fprintf(stderr, "error: premature EOF reading from %s\n", + str2ind_tab_filename); + exit(1); + } + lineno++; + cp = index(linebuf, '\n'); + if (!cp) { + fprintf(stderr, + "error: %s line %d is too long or unterminated\n", + str2ind_tab_filename, lineno); + exit(1); + } + *cp = '\0'; + if (cp > linebuf && cp[-1] == '\r') + cp[-1] = '\0'; +} + +static void +line_pure_num() +{ + char *cp; + + for (cp = linebuf; isspace(*cp); cp++) + ; + if (!isdigit(*cp)) { +inv: fprintf(stderr, "%s line %d: pure number expected\n", + str2ind_tab_filename, lineno); + exit(1); + } + while (isdigit(*cp)) + cp++; + if (*cp) + goto inv; +} + +static char * +copystr(str) + char *str; +{ + static char null = '\0'; + char *buf; + + if (str[0]) { + buf = malloc(strlen(str) + 1); + if (!buf) { + perror("malloc"); + exit(1); + } + strcpy(buf, str); + return(buf); + } else + return(&null); +} + +static void +process_record_line(idx) +{ + char *cp, *cp2; + int i; + + for (cp = linebuf; isspace(*cp); cp++) + ; + if (!isdigit(*cp)) { +syntaxerr: fprintf(stderr, "%s line %d: unexpected syntax\n", + str2ind_tab_filename, lineno); + exit(1); + } + while (isdigit(*cp)) + cp++; + if (*cp++ != ',') + goto syntaxerr; + i = atoi(linebuf); + if (i != idx) { + fprintf(stderr, "%s line %d lists wrong index (expected %d)\n", + str2ind_tab_filename, lineno, idx); + exit(1); + } + cp2 = index(cp, ','); + if (!cp2) + goto syntaxerr; + *cp2++ = '\0'; + str2ind_param_strings[idx] = copystr(cp); + str2ind_orig_strings[idx] = copystr(cp2); +} + +read_str2ind_tab() +{ + int idx; + + readF = fopen(str2ind_tab_filename, "r"); + if (!readF) { + perror(str2ind_tab_filename); + exit(1); + } + /* skip the timestamp line: the user is responsible for matching */ + read_line(); + line_pure_num(); + /* read the line with the array size */ + read_line(); + line_pure_num(); + str2ind_array_size = atoi(linebuf); + if (str2ind_array_size < 1) { + fprintf(stderr, "error: %s gives index array size < 1\n", + str2ind_tab_filename); + exit(1); + } + str2ind_orig_strings = malloc(sizeof(char *) * str2ind_array_size); + str2ind_param_strings = malloc(sizeof(char *) * str2ind_array_size); + if (!str2ind_orig_strings || !str2ind_param_strings) { + perror("malloc"); + exit(1); + } + for (idx = 0; idx < str2ind_array_size; idx++) { + read_line(); + process_record_line(idx); + } + fclose(readF); + return(0); +}