/* * 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: * * -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 *setmask; uint8_t *contents; WLINE **setlines; } ; 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; 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->setmask = calloc((spec->size+7)>>3,1); spec->contents = malloc(spec->size); spec->setlines = verbose ? malloc(spec->size*sizeof(*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],"-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 char *data, uint32_t d0, int dn, const char *line, WLINE **wlp) { int so; int sn; WLINE *wl; if (d0 < spec->base) { data += (spec->base - d0) * 3; dn -= spec->base - d0; d0 = spec->base; } so = d0 - spec->base; sn = spec->size - so; if (dn > sn) dn = sn; for (;dn>0;so++,dn--) { spec->contents[so] = (xdv(data[1]) * 16) + xdv(data[2]); spec->setmask[so>>3] |= 1U << (so & 7); if (verbose) { wl = *wlp; if (! wl) { wl = malloc(sizeof(WLINE)); wl->text = strdup(line); wl->refcnt = 0; *wlp = wl; } wl->refcnt ++; spec->setlines[so] = wl; } data += 3; } } 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; 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; 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++ != '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; n = 0; while ((s[0] == ' ') && Cisxdigit(s[1]) && Cisxdigit(s[2])) { n ++; s += 3; } if (s[0]) break <"handle">; if (n < 1) break <"handle">; for (sx=nspecs-1;sx>=0;sx--) { spec = &specs[sx]; if ((spec->end <= v32) || (v32+n <= spec->base)) continue; fill_spec(spec,s-(3*n),v32,n,b,&wl); } } while (0); l = 0; } } free(b); } static void dump_contents(void) { int sx; SPEC *s; uint32_t si; WLINE *wl; const char *pref; int pns; for (sx=0;sxbase); if (verbose) { wl = 0; pns = 0; for (si=0;sisize;si++) { if (s->setmask[si>>3] & (1U << (si & 7))) { if (pns || (s->setlines[si] != wl)) { if (!pns && wl) printf(": %s",wl->text); printf("\n"); pref = "\t"; } else { pref = " "; } printf("%s%02x",pref,s->contents[si]); pns = 0; wl = s->setlines[si]; } else { if (! pns) { if (wl) printf(": %s",wl->text); printf("\n"); pref = "\t"; } else { pref = " "; } printf("%s??",pref); pns = 1; } } if (!pns && wl) printf(": %s",wl->text); } else { for (si=0;sisize;si++) { if (s->setmask[si>>3] & (1U << (si & 7))) { printf(" %02x",s->contents[si]); } else { printf(" ??"); } } } printf("\n"); } } int main(int, char **); int main(int ac, char **av) { setup(ac,av); process(); dump_contents(); return(0); }