1: /* 2: * Program Name: symorder.c 3: * Date: January 21, 1994 4: * Author: S.M. Schultz 5: * 6: * ----------------- Modification History --------------- 7: * Version Date Reason For Modification 8: * 1.0 21Jan94 1. Initial release into the public domain. 9: */ 10: 11: /* 12: * This program reorders the symbol table of an executable. This is 13: * done by moving symbols found in the second file argument (one symbol 14: * per line) to the front of the symbol table. 15: * 16: * NOTE: This program needs to hold the string table in memory. 17: * For the kernel which has not been 'strcompact'd this is about 21kb. 18: * It is highly recommended that 'strcompact' be run first - that program 19: * removes redundant strings, significantly reducing the amount of memory 20: * needed. Running 'symcompact' will reduce the run time needed by 21: * this program by eliminating redundant non-overlaid text symbols. 22: */ 23: 24: #include <stdio.h> 25: #include <a.out.h> 26: #include <ctype.h> 27: #include <signal.h> 28: #include <string.h> 29: #include <sysexits.h> 30: #include <sys/file.h> 31: 32: #define NUMSYMS 125 33: char *order[NUMSYMS]; 34: int nsorted; 35: char *Pgm; 36: void cleanup(); 37: static char sym1tmp[20], sym2tmp[20], strtmp[20]; 38: static char *strtab, *oldname; 39: 40: main(argc, argv) 41: int argc; 42: char **argv; 43: { 44: FILE *fp, *fp2, *sym1fp, *sym2fp, *strfp; 45: int cnt, nsyms, len, c; 46: char fbuf1[BUFSIZ], fbuf2[BUFSIZ]; 47: off_t symoff, stroff, ltmp; 48: long strsiz; 49: struct nlist sym; 50: struct xexec xhdr; 51: 52: Pgm = argv[0]; 53: 54: signal(SIGQUIT, cleanup); 55: signal(SIGINT, cleanup); 56: signal(SIGHUP, cleanup); 57: 58: if (argc != 3) 59: { 60: fprintf(stderr, "usage %s: symlist file\n", Pgm); 61: exit(EX_USAGE); 62: } 63: fp = fopen(argv[2], "r+"); 64: if (!fp) 65: { 66: fprintf(stderr, "%s: can't open '%s' for update\n", Pgm, 67: argv[2]); 68: exit(EX_NOINPUT); 69: } 70: setbuf(fp, fbuf1); 71: cnt = fread(&xhdr, 1, sizeof (xhdr), fp); 72: if (cnt < sizeof (xhdr.e)) 73: { 74: fprintf(stderr, "%s: Premature EOF reading header\n", Pgm); 75: exit(EX_DATAERR); 76: } 77: if (N_BADMAG(xhdr.e)) 78: { 79: fprintf(stderr, "%s: Bad magic number\n", Pgm); 80: exit(EX_DATAERR); 81: } 82: nsyms = xhdr.e.a_syms / sizeof (struct nlist); 83: if (!nsyms) 84: { 85: fprintf(stderr, "%s: '%s' stripped\n", Pgm); 86: exit(EX_OK); 87: } 88: stroff = N_STROFF(xhdr); 89: symoff = N_SYMOFF(xhdr); 90: /* 91: * Seek to the string table size longword and read it. Then attempt to 92: * malloc memory to hold the string table. First make a sanity check on 93: * the size. 94: */ 95: fseek(fp, stroff, L_SET); 96: fread(&strsiz, sizeof (long), 1, fp); 97: if (strsiz > 48 * 1024L) 98: { 99: fprintf(stderr, "%s: string table > 48kb\n", Pgm); 100: exit(EX_DATAERR); 101: } 102: strtab = (char *)malloc((int)strsiz); 103: if (!strtab) 104: { 105: fprintf(stderr, "%s: no memory for strings\n", Pgm); 106: exit(EX_OSERR); 107: } 108: /* 109: * Now read the string table into memory. Reduce the size read because 110: * we've already retrieved the string table size longword. Adjust the 111: * address used so that we don't have to adjust each symbol table entry's 112: * string offset. 113: */ 114: cnt = fread(strtab + sizeof (long), 1, (int)strsiz - sizeof (long), fp); 115: if (cnt != (int)strsiz - sizeof (long)) 116: { 117: fprintf(stderr, "%s: Premature EOF reading strings\n", Pgm); 118: exit(EX_DATAERR); 119: } 120: /* 121: * Now open the file containing the list of symbols to 122: * relocate to the front of the symbol table. 123: */ 124: fp2 = fopen(argv[1], "r"); 125: if (!fp2) 126: { 127: fprintf(stderr, "%s: Can not open '%s'\n", Pgm, argv[1]); 128: exit(EX_NOINPUT); 129: } 130: getsyms(fp2); 131: 132: /* 133: * Create the temporary files which will hold the new symbol table and the 134: * new string table. One temp file receives symbols _in_ the list, 135: * another file receives all other symbols, and the last file receives the 136: * new string table. 137: */ 138: strcpy(sym1tmp, "/tmp/sym1XXXXXX"); 139: mktemp(sym1tmp); 140: strcpy(sym2tmp, "/tmp/sym2XXXXXX"); 141: mktemp(sym2tmp); 142: strcpy(strtmp, "/tmp/strXXXXXX"); 143: mktemp(strtmp); 144: sym1fp = fopen(sym1tmp, "w+"); 145: sym2fp = fopen(sym2tmp, "w+"); 146: strfp = fopen(strtmp, "w+"); 147: if (!sym1fp || !sym2fp || !strfp) 148: { 149: fprintf(stderr, "%s: Can't create %s, %s or %s\n", sym1tmp, 150: sym2tmp, strtmp); 151: exit(EX_CANTCREAT); 152: } 153: setbuf(sym1fp, fbuf2); 154: /* 155: * Now position the executable to the start of the symbol table. For each 156: * symbol scan the list for a match on the symbol name. If the 157: * name matches write the symbol table entry to one tmp file, else write it 158: * to the second symbol tmp file. 159: * 160: * NOTE: Since the symbol table is being rearranged the usefulness of 161: * "local" symbols, especially 'register' symbols, is greatly diminished 162: * Not that they are terribly useful in any event - especially the register 163: * symbols, 'adb' claims to do something with them but doesn't. In any 164: * event this suite of programs is targeted at the kernel and the register 165: * local symbols are of no use. For this reason 'register' symbols are 166: * removed - this has the side effect of even further reducing the symbol 167: * and string tables that must be processed by 'nm', 'ps', 'adb' and so on. 168: * This removal probably should have been done earlier - in 'strcompact' or 169: * 'symcompact' and it may be in the future, but for now just do it here. 170: */ 171: fseek(fp, symoff, L_SET); 172: while (nsyms--) 173: { 174: fread(&sym, sizeof (sym), 1, fp); 175: if (sym.n_type == N_REG) 176: continue; 177: if (inlist(&sym)) 178: fwrite(&sym, sizeof (sym), 1, sym1fp); 179: else 180: fwrite(&sym, sizeof (sym), 1, sym2fp); 181: } 182: 183: /* 184: * Position the executable file to where the symbol table starts. Truncate 185: * the file to the current position to remove the old symbols and strings. Then 186: * write the symbol table entries which are to appear at the front, followed 187: * by the remainder of the symbols. As each symbol is processed adjust the 188: * string table offset and write the string to the strings tmp file. 189: * 190: * It was either re-scan the tmp files with the symbols again to retrieve 191: * the string offsets or simply write the strings to yet another tmp file. 192: * The latter was chosen. 193: */ 194: fseek(fp, symoff, L_SET); 195: ftruncate(fileno(fp), ftell(fp)); 196: ltmp = sizeof (long); 197: rewind(sym1fp); 198: rewind(sym2fp); 199: nsyms = 0; 200: while (fread(&sym, sizeof (sym), 1, sym1fp) == 1) 201: { 202: if (ferror(sym1fp) || feof(sym1fp)) 203: break; 204: oldname = strtab + (int)sym.n_un.n_strx; 205: sym.n_un.n_strx = ltmp; 206: len = strlen(oldname) + 1; 207: ltmp += len; 208: fwrite(&sym, sizeof (sym), 1, fp); 209: fwrite(oldname, len, 1, strfp); 210: nsyms++; 211: } 212: fclose(sym1fp); 213: while (fread(&sym, sizeof (sym), 1, sym2fp) == 1) 214: { 215: if (ferror(sym2fp) || feof(sym2fp)) 216: break; 217: oldname = strtab + (int)sym.n_un.n_strx; 218: sym.n_un.n_strx = ltmp; 219: len = strlen(oldname) + 1; 220: ltmp += len; 221: fwrite(&sym, sizeof (sym), 1, fp); 222: fwrite(oldname, len, 1, strfp); 223: nsyms++; 224: } 225: fclose(sym2fp); 226: /* 227: * Next write the symbol table size longword followed by the 228: * string table itself. 229: */ 230: fwrite(<mp, sizeof (long), 1, fp); 231: rewind(strfp); 232: while ((c = getc(strfp)) != EOF) 233: putc(c, fp); 234: fclose(strfp); 235: /* 236: * And last (but not least) we need to update the a.out header with 237: * the correct size of the symbol table. 238: */ 239: rewind(fp); 240: xhdr.e.a_syms = nsyms * sizeof (struct nlist); 241: fwrite(&xhdr.e, sizeof (xhdr.e), 1, fp); 242: fclose(fp); 243: free(strtab); 244: cleanup(); 245: } 246: 247: inlist(sp) 248: register struct nlist *sp; 249: { 250: register int i; 251: 252: for (i = 0; i < nsorted; i++) 253: { 254: if (strcmp(strtab + (int)sp->n_un.n_strx, order[i]) == 0) 255: return(1); 256: } 257: return(0); 258: } 259: 260: getsyms(fp) 261: FILE *fp; 262: { 263: char asym[128], *start; 264: register char *t, **p; 265: 266: for (p = order; fgets(asym, sizeof(asym), fp) != NULL;) 267: { 268: if (nsorted >= NUMSYMS) 269: { 270: fprintf(stderr, "%s: only doing %d symbols\n", 271: Pgm, NUMSYMS); 272: break; 273: } 274: for (t = asym; isspace(*t); ++t) 275: ; 276: if (!*(start = t)) 277: continue; 278: while (*++t) 279: ; 280: if (*--t == '\n') 281: *t = '\0'; 282: *p++ = strdup(start); 283: ++nsorted; 284: } 285: fclose(fp); 286: } 287: 288: void 289: cleanup() 290: { 291: if (strtmp[0]) 292: unlink(strtmp); 293: if (sym1tmp[0]) 294: unlink(sym1tmp); 295: if (sym2tmp[0]) 296: unlink(sym2tmp); 297: exit(EX_OK); 298: }