/* * xcoffdump - read 32-bit XCOFF files (and members of AIX big archives) * directly, reproducing the parts of AIX dump(1) listed below. * * usage: xcoffdump [-o] [-h] [-H] [-T] file[(member)] * -o file and optional (auxiliary) header (like dump -X32 -o) * -h section headers (like dump -X32 -h) * -H loader header and import file strings (like dump -X32 -H) * -T loader symbol table (like dump -X32 -Tv) * * Layout notes (AIX 4.3.3 headers, checked against the bytes): * file header 20 bytes, magic 0x01DF; aux header f_opthdr bytes (72 for * executables); section headers 40 bytes each. The .loader section * starts with a 32-byte header; loader symbols (24 bytes) follow it, * then relocations (12 bytes); l_impoff and l_stoff are relative to the * start of the section. */ #include #include #include #define FILHSZ 20 #define SCNHSZ 40 #define LDHDRSZ 32 #define LDSYMSZ 24 struct buf { unsigned char *p; unsigned long len; }; static struct buf f; /* the whole file */ static unsigned long base; /* start of the XCOFF image (archive member) */ static char *name; /* name to print in headings */ static unsigned long u32(unsigned long off) { unsigned char *q; off += base; if (off + 4 > f.len) { fprintf(stderr, "xcoffdump: read past end at 0x%lx\n", off); exit(2); } q = f.p + off; return ((unsigned long)q[0] << 24) | ((unsigned long)q[1] << 16) | ((unsigned long)q[2] << 8) | q[3]; } static unsigned int u16(unsigned long off) { off += base; if (off + 2 > f.len) { fprintf(stderr, "xcoffdump: read past end at 0x%lx\n", off); exit(2); } return (f.p[off] << 8) | f.p[off + 1]; } static unsigned char * at(unsigned long off) { return f.p + base + off; } static int slurp(char *path) { FILE *fp; long n; if ((fp = fopen(path, "r")) == NULL) return -1; fseek(fp, 0L, SEEK_END); n = ftell(fp); rewind(fp); f.len = n; if ((f.p = malloc(n + 1)) == NULL || fread(f.p, 1, n, fp) != (size_t)n) { fclose(fp); return -1; } fclose(fp); return 0; } /* * AIX big archive ("\n"): fixed header has decimal ASCII fields; * fl_fstmoff (offset of first member) at 68, 20 chars. Each member * header: ar_size[20] ar_nxtmem[20] ar_prvmem[20] ar_date[12] ar_uid[12] * ar_gid[12] ar_mode[12] ar_namlen[4], then the name, padded to even, * then "`\n", then the member data. */ static long dec(unsigned char *s, int n) { char tmp[32]; memcpy(tmp, s, n); tmp[n] = '\0'; return atol(tmp); } static int findmember(char *member) { long off, namlen; if (f.len < 128 || memcmp(f.p, "\n", 8) != 0) { fprintf(stderr, "xcoffdump: not a big archive\n"); return -1; } off = dec(f.p + 68, 20); while (off > 0 && off + 112 < (long)f.len) { namlen = dec(f.p + off + 108, 4); if (namlen == (long)strlen(member) && memcmp(f.p + off + 112, member, namlen) == 0) { base = off + 112 + namlen + (namlen & 1) + 2; return 0; } off = dec(f.p + off + 20, 20); /* ar_nxtmem */ } fprintf(stderr, "xcoffdump: member %s not found\n", member); return -1; } static char * secname(int n) { static char s[9]; int nscns = u16(2), opthdr = u16(16); if (n < 1 || n > nscns) return "undef"; memcpy(s, at(FILHSZ + opthdr + (n - 1) * SCNHSZ), 8); s[8] = '\0'; return s; } /* section header offset of the first section with the given flag, or 0 */ static unsigned long findscn(unsigned long flag) { int i, nscns = u16(2), opthdr = u16(16); unsigned long sh; for (i = 0; i < nscns; i++) { sh = FILHSZ + opthdr + i * SCNHSZ; if ((u32(sh + 36) & 0xffff) == flag) return sh; } return 0; } static void heading(char *what) { printf("\n%s:\n\n\t\t\t***%s***\n", name, what); } static void do_o(void) { int opthdr = u16(16); heading("Object Module Header"); printf("# Sections Symbol Ptr # Symbols Opt Hdr Len Flags\n"); printf("%10d\t0x%08lx\t%9ld\t%10d\t0x%04x\n", u16(2), u32(8), (long)u32(12), opthdr, u16(18)); printf("Timestamp = %ld\n", (long)u32(4)); printf("Magic = 0x%x \n", u16(0)); if (opthdr < 72) return; printf("\n\t\t\t***Optional Header***\n"); printf("Tsize Dsize Bsize Tstart Dstart\n"); printf("0x%08lx 0x%08lx 0x%08lx 0x%08lx 0x%08lx\n", u32(FILHSZ + 4), u32(FILHSZ + 8), u32(FILHSZ + 12), u32(FILHSZ + 20), u32(FILHSZ + 24)); printf("\nSNloader SNentry SNtext\t SNtoc SNdata\n"); printf("0x%04x 0x%04x 0x%04x 0x%04x 0x%04x \n", u16(FILHSZ + 40), u16(FILHSZ + 32), u16(FILHSZ + 34), u16(FILHSZ + 38), u16(FILHSZ + 36)); printf("\nTXTalign DATAalign TOC vstamp entry\n"); printf("0x%04x 0x%04x 0x%08lx 0x%04x 0x%08lx\n", u16(FILHSZ + 44), u16(FILHSZ + 46), u32(FILHSZ + 28), u16(FILHSZ + 2), u32(FILHSZ + 16)); printf("\nmaxSTACK maxDATA SNbss magic modtype\n"); printf("0x%08lx 0x%08lx 0x%04x 0x%04x %c%c\n", u32(FILHSZ + 52), u32(FILHSZ + 56), u16(FILHSZ + 42), u16(FILHSZ + 0), *at(FILHSZ + 48), *at(FILHSZ + 49)); } static void do_h(void) { int i, nscns = u16(2), opthdr = u16(16); unsigned long sh; heading("Section Header Information"); for (i = 0; i < nscns; i++) { sh = FILHSZ + opthdr + i * SCNHSZ; printf("\t \t \t Section Header for %-8.8s\n", (char *)at(sh)); printf("PHYaddr VTRaddr SCTsiz RAWptr RELptr\n"); printf("0x%08lx 0x%08lx 0x%08lx 0x%08lx 0x%08lx\n", u32(sh + 8), u32(sh + 12), u32(sh + 16), u32(sh + 20), u32(sh + 24)); printf("\nLN#ptr #RELent\t #LINent Flags\n"); printf("0x%08lx 0x%04x 0x%04x 0x%08lx\n\n", u32(sh + 28), u16(sh + 32), u16(sh + 34), u32(sh + 36)); } } /* import file id n: "path base member" triples, NUL-terminated */ static void impid(unsigned long ld, long n, char **path, char **b, char **mem) { char *s = (char *)at(ld + u32(ld + 20)); long i; for (i = 0; i < n; i++) { s += strlen(s) + 1; s += strlen(s) + 1; s += strlen(s) + 1; } *path = s; s += strlen(s) + 1; *b = s; s += strlen(s) + 1; *mem = s; } static void do_H(unsigned long ld) { long i; char *p, *b, *m; heading("Loader Section"); printf(" Loader Header Information\n"); printf("VERSION# #SYMtableENT #RELOCent LENidSTR\n"); printf("0x%08lx 0x%08lx 0x%08lx 0x%08lx \n\n", u32(ld), u32(ld + 4), u32(ld + 8), u32(ld + 12)); printf("#IMPfilID OFFidSTR LENstrTBL OFFstrTBL\n"); printf("0x%08lx 0x%08lx 0x%08lx 0x%08lx \n\n", u32(ld + 16), u32(ld + 20), u32(ld + 24), u32(ld + 28)); printf("\n\t\t\t***Import File Strings***\n"); printf("INDEX PATH BASE MEMBER \n"); for (i = 0; i < (long)u32(ld + 16); i++) { impid(ld, i, &p, &b, &m); printf("%-7ld%-30s%-20s%-20s\n", i, p, b, m); } } static char *xmc[] = { "PR", "RO", "DB", "TC", "UA", "RW", "GL", "XO", "SV", "BS", "DS", "UC", "TI", "TB", "??", "TC0", "TD", "SV64", "SV3264" }; static char *xty[] = { "EXTref", "SECdef", "LDdef", "BSS", "EMsym", "UNSet", "HLdef", "??" }; static void do_T(unsigned long ld) { long i, nsyms = u32(ld + 4); unsigned long s, stoff = u32(ld + 28); int t, scn; char nm[9], *sym, imp[64], *p, *b, *m, *imex; heading("Loader Section"); printf("\n\t\t\t***Loader Symbol Table Information***\n"); printf("[Index]\t Value Scn IMEX Sclass Type IMPid Name\n\n"); for (i = 0; i < nsyms; i++) { s = ld + LDHDRSZ + i * LDSYMSZ; if (u32(s) == 0) { sym = (char *)at(ld + stoff + u32(s + 4)); } else { memcpy(nm, at(s), 8); nm[8] = '\0'; sym = nm; } scn = (short)u16(s + 12); t = *at(s + 14); switch (t & 0x70) { case 0x40: imex = "IMP"; break; case 0x20: imex = "ENTpt"; break; case 0x10: imex = "EXP"; break; case 0x50: imex = "ImpExp"; break; case 0x00: imex = ""; break; default: imex = "?"; break; } if (u32(s + 16) == 0 || !(t & 0x40)) { strcpy(imp, "[noIMid]"); } else { impid(ld, u32(s + 16), &p, &b, &m); if (*m) sprintf(imp, "%.20s%.20s(%.20s)", p, b, m); else sprintf(imp, "%.20s%s%.20s", p, *p && strcmp(p, "/") ? "/" : "", b); } printf("[%ld]\t0x%08lx %8s %8s %6s %6s %16s %s\n", i, u32(s + 8), scn > 0 ? secname(scn) : "undef", imex, *at(s + 15) < 19 ? xmc[*at(s + 15)] : "??", xty[t & 7], imp, sym); } } int main(int argc, char **argv) { int i, o = 0, h = 0, H = 0, T = 0; char *path, *lp, *rp; unsigned long sh, ld; for (i = 1; i < argc && argv[i][0] == '-'; i++) { o |= strchr(argv[i], 'o') != NULL; h |= strchr(argv[i], 'h') != NULL; H |= strchr(argv[i], 'H') != NULL; T |= strchr(argv[i], 'T') != NULL; } if (i != argc - 1) { fprintf(stderr, "usage: xcoffdump [-o] [-h] [-H] [-T] file[(member)]\n"); return 1; } name = path = argv[i]; lp = strchr(path, '('); if (lp && (rp = strchr(lp, ')')) != NULL) { path = strdup(path); lp = strchr(path, '('); rp = strchr(lp, ')'); *lp = *rp = '\0'; } else lp = NULL; if (slurp(path) < 0) { perror(path); return 1; } if (lp && findmember(lp + 1) < 0) return 1; if (u16(0) != 0x01DF) { fprintf(stderr, "%s: not 32-bit XCOFF (magic 0x%04x)\n", name, u16(0)); return 1; } if (o) do_o(); if (h) do_h(); if (H || T) { if ((sh = findscn(0x1000)) == 0) { fprintf(stderr, "%s: no loader section\n", name); return 1; } ld = u32(sh + 20); if (H) do_H(ld); if (T) do_T(ld); } return 0; }