/* * Search through TRC_MEM output for references to a certain areas of * memory, tracking the contents of those areas. * * Usage: $0 [flags] spec [spec ...] * * Each spec can be begin-end or begin+size, where all numbers are in * hex. The lines being searched are taken from stdin. Specs always * include the base but not the end; to put it another way, the ranges * are [base,end). (The form with begin and size is equivalent to the * begin-and-end form where end equals begin+size.) * * By default, output consists of one line per spec, giving the base * and then the final contents, a la * * 12345678: 46 6f 6f 21 * * Bytes for which no contents are apparent are printed as ??. * * flags can be: * * -a * Print not just the final contents, but each time any of * the bytes of interest are changed. * -v * Print not only byte values but where they came from. * The output format changes, looking like * * 12345678: * 46: 474881: 416: w: 12345678: 46 46 46 81 * 6f: 474941: 416: w: 12345679: 6f * 6f 21: 475002: 416: w: 1234567a: 6f 21 */ #include #include #include #include #include extern const char *__progname; typedef unsigned long int ULI; typedef struct spec SPEC; typedef struct wline WLINE; struct wline { char *text; int refcnt; } ; struct spec { uint32_t base; uint32_t end; uint32_t size; uint8_t *mention; uint8_t *setmask; uint8_t *contents; WLINE **setlines; } ; static int all = 0; static int verbose = 0; static int nspecs; static SPEC *specs; #define Cisdigit(x) isdigit((unsigned char)(x)) #define Cisxdigit(x) isxdigit((unsigned char)(x)) static void parse_spec(const char *str, SPEC *spec) { unsigned long int v; uint32_t v32; char *ep; char sep; const char *n2str; int i; v = strtoul(str,&ep,16); if (ep == str) { fprintf(stderr,"%s: bad spec `%s' (no base address)\n",__progname,str); exit(1); } v32 = v; if (v32 != v) { fprintf(stderr,"%s: bad spec `%s' (out-of-range base address)\n",__progname,str); exit(1); } spec->base = v32; str = ep; sep = *str++; switch (sep) { case '-': n2str = "end address"; break; case '+': n2str = "size"; break; default: fprintf(stderr,"%s: bad spec `%s' (invalid separator)\n",__progname,str); exit(1); break; } v = strtoul(str,&ep,16); if (ep == str) { fprintf(stderr,"%s: bad spec `%s' (no %s)\n",__progname,str,n2str); exit(1); } if (*ep) { fprintf(stderr,"%s: bad spec `%s' (junk after %s)\n",__progname,str,n2str); exit(1); } v32 = v; if (v32 != v) { fprintf(stderr,"%s: bad spec `%s' (out-of-range %s)\n",__progname,str,n2str); exit(1); } switch (sep) { case '-': spec->end = v32; break; case '+': spec->end = spec->base + v32; break; default: abort(); break; } spec->size = spec->end - spec->base; spec->mention = calloc(1,(spec->size+7)>>3); spec->setmask = malloc(spec->size); spec->contents = malloc(spec->size); if (verbose) { spec->setlines = malloc(spec->size*sizeof(*spec->setlines)); for (i=spec->size-1;i>=0;i--) spec->setlines[i] = 0; } else { spec->setlines = 0; } } static void setup(int ac, char **av) { int i; int errs; errs = 0; while ((ac >= 2) && (av[1][0] == '-')) { i = 1; if (! strcmp(av[1],"-a")) { all = 1; } else if (! strcmp(av[1],"-v")) { verbose = 1; } else { fprintf(stderr,"%s: unrecognized flag `%s'\n",__progname,av[1]); errs = 1; } ac -= i; av += i; } if (ac < 2) { fprintf(stderr,"Usage: %s [flags] spec [spec ...]\n",__progname); exit(1); } nspecs = ac - 1; specs = malloc(nspecs*sizeof(SPEC)); for (i=nspecs-1;i>=0;i--) parse_spec(av[i+1],&specs[i]); } static int xdv(char d) { switch (d) { case '0': return(0); break; case '1': return(1); break; case '2': return(2); break; case '3': return(3); break; case '4': return(4); break; case '5': return(5); break; case '6': return(6); break; case '7': return(7); break; case '8': return(8); break; case '9': return(9); break; case 'a': case 'A': return(10); break; case 'b': case 'B': return(11); break; case 'c': case 'C': return(12); break; case 'd': case 'D': return(13); break; case 'e': case 'E': return(14); break; case 'f': case 'F': return(15); break; } abort(); } static void fill_spec(SPEC *spec, const unsigned char *val, const unsigned char *def, uint32_t at, int n, const char *line, WLINE **wlp) { int so; int sn; WLINE *wl; WLINE *owl; int i; if (at < spec->base) { val += spec->base - at; def += spec->base - at; n -= spec->base - at; at = spec->base; } if (n < 1) abort(); so = at - spec->base; sn = spec->size - so; if (n > sn) n = sn; if (n < 1) abort(); if (all) printf("%s\n",line); for (i=0;n>0;so++,n--,i++) { spec->contents[so] = val[i]; spec->setmask[so] = def[i]; spec->mention[so>>3] |= 1 << (so & 7); if (verbose) { wl = *wlp; if (! wl) { wl = malloc(sizeof(WLINE)); wl->text = strdup(line); wl->refcnt = 0; *wlp = wl; } owl = spec->setlines[so]; wl->refcnt ++; spec->setlines[so] = wl; if (owl) { owl->refcnt --; // XXX do freeing if refcnt is zero? } } } } static void process(void) { char *b; int l; int a; int c; const char *s; unsigned long int uli; uint32_t v32; char *ep; // int n; int sx; SPEC *spec; WLINE *wl; unsigned char dataval[16]; unsigned char datadef[16]; int dx; b = 0; a = 0; l = 0; while (1) { c = getchar(); if (c == EOF) { if (l > 0) fprintf(stderr,"%s: partial line ignored at end of input\n",__progname); break; } if (l >= a) b = realloc(b,a=l+8); b[l++] = c; if (c == '\n') { b[--l] = '\0'; wl = 0; dx = 0; do <"handle"> { s = b; while (*s && Cisdigit(*s)) s ++; if (*s++ != ':') break <"handle">; if (*s++ != ' ') break <"handle">; while (*s && Cisdigit(*s)) s ++; if (*s++ != ':') break <"handle">; if (*s++ != ' ') break <"handle">; if (*s++ != '[') break <"handle">; if (*s++ != 'm') break <"handle">; if (*s++ != 'e') break <"handle">; if (*s++ != 'm') break <"handle">; if (*s++ != ']') break <"handle">; if (*s++ != ' ') break <"handle">; if (*s++ != 'w') break <"handle">; if (*s++ != ':') break <"handle">; if (*s++ != ' ') break <"handle">; uli = strtoul(s,&ep,16); if (ep == s) break <"handle">; if (*ep != ':') break <"handle">; v32 = uli; if (v32 != uli) break <"handle">; s = ep + 1; while (1) { if (! s[0]) break; if (s[0] != ' ') break <"handle">; s ++; if (dx == 8) { if (s[0] != ' ') break <"handle">; s ++; } if (dx >= 16) break <"handle">; if ((s[0] == ' ') && (s[1] == ' ')) { if (dx != 0) break <"handle">; s += 2; v32 ++; continue; } if ( (Cisxdigit(s[0]) || (s[0] == '?')) && (Cisxdigit(s[1]) || (s[1] == '?')) ) { if (s[0] == '?') { dataval[dx] = 0; datadef[dx] &= ~0xf0; } else { dataval[dx] = xdv(s[0]) << 4; datadef[dx] |= 0xf0; } if (s[1] == '?') { datadef[dx] &= ~0x0f; } else { dataval[dx] |= xdv(s[0]); datadef[dx] |= 0x0f; } s += 2; dx ++; continue; } if ( (s[0] == '<') && ((s[1] == '0') || (s[1] == '1') || (s[1] == '?')) && ((s[2] == '0') || (s[2] == '1') || (s[2] == '?')) && ((s[3] == '0') || (s[3] == '1') || (s[3] == '?')) && ((s[4] == '0') || (s[4] == '1') || (s[4] == '?')) && ((s[5] == '0') || (s[5] == '1') || (s[5] == '?')) && ((s[6] == '0') || (s[6] == '1') || (s[6] == '?')) && ((s[7] == '0') || (s[7] == '1') || (s[7] == '?')) && ((s[8] == '0') || (s[8] == '1') || (s[8] == '?')) && (s[9] == '>') ) { dataval[dx] = ((s[1] == '1') << 7) | ((s[2] == '1') << 6) | ((s[3] == '1') << 5) | ((s[4] == '1') << 4) | ((s[5] == '1') << 3) | ((s[6] == '1') << 2) | ((s[7] == '1') << 1) | (s[8] == '1'); datadef[dx] = ((s[1] != '?') << 7) | ((s[2] != '?') << 6) | ((s[3] != '?') << 5) | ((s[4] != '?') << 4) | ((s[5] != '?') << 3) | ((s[6] != '?') << 2) | ((s[7] != '?') << 1) | (s[8] != '?'); s += 10; dx ++; continue; } break <"handle">; } if (dx < 1) break <"handle">; for (sx=nspecs-1;sx>=0;sx--) { spec = &specs[sx]; if ((spec->end <= v32) || (v32+dx <= spec->base)) continue; fill_spec(spec,&dataval[0],&datadef[0],v32,dx,b,&wl); } } while (0); l = 0; } } free(b); } static void print_mask_val(unsigned char mask, unsigned char val) { switch (mask) { case 0x00: printf("??"); break; case 0x0f: printf("?%x",val&0x0f); break; case 0xf0: printf("%x?",(val>>4)&0x0f); break; case 0xff: printf("%02x",val); break; default: printf("<%c%c%c%c%c%c%c%c>", (mask & 0x80) ? (val & 0x80) ? '1' : '0' : '?', (mask & 0x40) ? (val & 0x40) ? '1' : '0' : '?', (mask & 0x20) ? (val & 0x20) ? '1' : '0' : '?', (mask & 0x10) ? (val & 0x10) ? '1' : '0' : '?', (mask & 0x08) ? (val & 0x08) ? '1' : '0' : '?', (mask & 0x04) ? (val & 0x04) ? '1' : '0' : '?', (mask & 0x02) ? (val & 0x02) ? '1' : '0' : '?', (mask & 0x01) ? (val & 0x01) ? '1' : '0' : '?' ); break; } } static void dump_contents(void) { int sx; SPEC *s; uint32_t si; WLINE *wl; const char *pref; int any; for (sx=0;sxbase); if (verbose) { wl = 0; any = 0; for (si=0;sisize;si++) { if (any || (s->setlines[si] != wl)) { if (!any && wl) printf(": %s",wl->text); printf("\n"); pref = "\t"; } if (s->mention[si>>3] & (1 << (si&7))) { printf("%s",pref); print_mask_val(s->setmask[si],s->contents[si]); } else { printf("%s--",pref); } any = 1; } if (! any) abort(); } else { for (si=0;sisize;si++) { if (s->mention[si>>3] & (1 << (si&7))) { putchar(' '); print_mask_val(s->setmask[si],s->contents[si]); } } } printf("\n"); } } int main(int, char **); int main(int ac, char **av) { setup(ac,av); process(); dump_contents(); return(0); }