FreeCalypso > hg > freecalypso-reveng
view objgrep/frontend.c @ 389:623316d1ece7
compal/iMelody: capturing initial observations
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Thu, 31 Mar 2022 20:56:56 +0000 |
parents | 928ed52930aa |
children |
line wrap: on
line source
/* * This program is a front-end to objgrep. It takes an ASCII text file as * input that lists the modules and sections to be grepped for, and it * invokes objgrep via popen() for each listed section, all on the same * unknown binary. We collect the symbol addresses printed by objgrep * via our pipe, and then we sort them to produce the final report. */ #include <stdio.h> #include <stdlib.h> #include <ctype.h> #include <string.h> #include <strings.h> #include <unistd.h> #define RAM_BOUNDARY 0x800000 #define SYMFLAG_AMBIG 8 #define SYMSRC_TEXTMATCH 4 #define SYMSRC_EXTRELOC 2 #define SYMSRC_INTRELOC 1 struct symbol { char *name; unsigned value; int flags; struct symbol *next; }; struct symbol *flash_symbols, *ram_symbols; unsigned num_flash_symbols, num_ram_symbols; char *binfilename; int verbose; enter_symbol(name, valstr, symsrc) char *name, *valstr; { struct symbol *newsym; newsym = malloc(sizeof(struct symbol) + strlen(name) + 1); if (!newsym) { perror("malloc"); exit(1); } newsym->name = (char *)(newsym + 1); strcpy(newsym->name, name); newsym->value = strtoul(valstr, 0, 16); newsym->flags = symsrc; if (newsym->value < RAM_BOUNDARY) { newsym->next = flash_symbols; flash_symbols = newsym; num_flash_symbols++; } else { newsym->next = ram_symbols; ram_symbols = newsym; num_ram_symbols++; } } process_section(objfile, secname) char *objfile, *secname; { char cmdline[1024], linebuf[512], *cp, *fields[3]; FILE *f; int symsrc, i; static char headline_textmatch[] = "This source section's symbols:"; static char headline_extreloc[] = "Externals deduced from relocs:"; static char headline_intreloc[] = "This module's symbols deduced from section relocs:"; sprintf(cmdline, "objgrep -rs %s %s %s", objfile, secname, binfilename); if (verbose) printf("Running %s\n", cmdline); f = popen(cmdline, "r"); if (!f) { perror("popen"); exit(1); } symsrc = 0; while (fgets(linebuf, sizeof linebuf, f)) { cp = index(linebuf, '\n'); if (!cp) { fprintf(stderr, "error: objgrep output line has no terminating newline\n"); exit(1); } *cp = '\0'; if (!strcmp(linebuf, headline_textmatch)) { symsrc = SYMSRC_TEXTMATCH; continue; } if (!strcmp(linebuf, headline_extreloc)) { symsrc = SYMSRC_EXTRELOC; continue; } if (!strcmp(linebuf, headline_intreloc)) { symsrc = SYMSRC_INTRELOC; continue; } cp = linebuf; for (i = 0; ; i++) { while (isspace(*cp)) cp++; if (!*cp) break; if (i == 3) { i++; break; } for (fields[i] = cp; *cp && !isspace(*cp); cp++) ; if (*cp) *cp++ = '\0'; } if (i != 3) continue; if (fields[1][0] != '=' || fields[1][1]) continue; if (!symsrc) { fprintf(stderr, "error: symbol output from objgrep w/o source indication\n"); exit(1); } enter_symbol(fields[0], fields[2], symsrc); } pclose(f); } process_list_file(listfilename) char *listfilename; { FILE *f; char linebuf[512], *objname, *cp, *np; int lineno; f = fopen(listfilename, "r"); if (!f) { perror(listfilename); exit(1); } for (lineno = 1; fgets(linebuf, sizeof linebuf, f); lineno++) { for (cp = linebuf; isspace(*cp); cp++) ; if (*cp == '\0' || *cp == '#') continue; for (objname = cp; *cp && !isspace(*cp); cp++) ; if (*cp) *cp++ = '\0'; while (isspace(*cp)) cp++; if (*cp == '\0' || *cp == '#') { process_section(objname, ".text"); continue; } while (*cp && *cp != '#') { for (np = cp; *cp && !isspace(*cp); cp++) ; if (*cp) *cp++ = '\0'; process_section(objname, np); while (isspace(*cp)) cp++; } } fclose(f); } sort_by_value(sym1, sym2) struct symbol **sym1, **sym2; { if ((*sym1)->value < (*sym2)->value) return(-1); if ((*sym1)->value > (*sym2)->value) return(1); return(0); } sort_by_name(sym1, sym2) struct symbol **sym1, **sym2; { int i; i = strcmp((*sym1)->name, (*sym2)->name); if (i) return i; else return sort_by_value(sym1, sym2); } fill_input_array(head, buf) struct symbol *head, **buf; { struct symbol *sym, **p; p = buf; for (sym = head; sym; sym = sym->next) *p++ = sym; } unsigned dedup_symbols(inbuf, outbuf, total) struct symbol **inbuf, **outbuf; unsigned total; { struct symbol **ip, **op, **input_end, *nsym; op = outbuf; input_end = inbuf + total; for (ip = inbuf; ip < input_end; ip++) { nsym = *ip; if (op == outbuf || strcmp(nsym->name, op[-1]->name)) { *op++ = nsym; continue; } if (nsym->value == op[-1]->value) { op[-1]->flags |= nsym->flags; continue; } op[-1]->flags |= SYMFLAG_AMBIG; nsym->flags |= SYMFLAG_AMBIG; *op++ = nsym; } return(op - outbuf); } emit_final_symbols(buf, total) struct symbol **buf; unsigned total; { struct symbol **p, **endbuf, *sym; endbuf = buf + total; for (p = buf; p < endbuf; p++) { sym = *p; printf("%08X %s (", sym->value, sym->name); if (sym->flags & SYMSRC_TEXTMATCH) putchar('S'); if (sym->flags & SYMSRC_EXTRELOC) putchar('R'); if (sym->flags & SYMSRC_INTRELOC) putchar('r'); if (sym->flags & SYMFLAG_AMBIG) fputs(", ambiguous", stdout); putchar(')'); putchar('\n'); } } sort_and_emit_symbols(head, total) struct symbol *head; unsigned total; { struct symbol **input, **output; unsigned final_count; if (verbose) printf("Total symbols to process: %u\n", total); input = malloc(sizeof(void *) * total); if (!input) { perror("malloc"); exit(1); } if (verbose) printf("Turning linked list into linear array\n"); fill_input_array(head, input); if (verbose) printf("Sorting by name\n"); qsort(input, total, sizeof(void *), sort_by_name); if (verbose) printf("Allocating output array\n"); output = malloc(sizeof(void *) * total); if (!output) { perror("malloc"); exit(1); } if (verbose) printf("Processing duplicates\n"); final_count = dedup_symbols(input, output, total); free(input); if (verbose) printf("%u symbols left, sorting by value\n", final_count); qsort(output, final_count, sizeof(void *), sort_by_value); emit_final_symbols(output, final_count); free(output); putchar('\n'); } main(argc, argv) char **argv; { int c; extern int optind; while ((c = getopt(argc, argv, "v")) != EOF) switch (c) { case 'v': verbose++; continue; default: usage: fprintf(stderr, "usage: %s [-v] listfile binfile\n", argv[0]); exit(1); } if (argc - optind != 2) goto usage; binfilename = argv[optind+1]; process_list_file(argv[optind]); if (flash_symbols) { printf("Flash symbols:\n\n"); sort_and_emit_symbols(flash_symbols, num_flash_symbols); } if (ram_symbols) { printf("RAM symbols:\n\n"); sort_and_emit_symbols(ram_symbols, num_ram_symbols); } exit(0); }