/* qarch.c: Utility to find out which compiler and -qarch options were used for a binary. Copyright: Fred Hucht (fred@thp.Uni-Dusiburg.DE) and Michael Staats (michael@thp.Uni-Dusiburg.DE) Free software according GNU Public license Thanks to Thomas Braunbeck (braunbec@mainz.ibm.de), AS Software Service AIX, Germany Compilation: either "make qarch" or "cc -O -o qarch qarch.c" */ #define VERSION "1.1" static char *What[] = { "@(#)qarch V " VERSION " (C) F. Hucht & M. Staats", "@(#)Email: michael@thp.Uni-Duisburg.DE", "@(#) fred@thp.Uni-Duisburg.DE"}; #include #include #include #include #include #include #include /* Under AIX4, these are in */ #ifndef TCPU_INVALID # define TCPU_INVALID 0 # define TCPU_PPC 1 # define TCPU_PPC64 2 # define TCPU_COM 3 # define TCPU_PWR 4 # define TCPU_ANY 5 # define TCPU_601 6 # define TCPU_PWR1 10 # define TCPU_PWRX 224 #endif struct TypeNames { short n; const char *s; } CPUTypes[] = { TCPU_INVALID, "Invalid", TCPU_PPC, "PowerPC32", TCPU_PPC64, "PowerPC64", TCPU_COM, "Common", TCPU_PWR, "POWER", TCPU_ANY, "Any", TCPU_601, "PPC601", TCPU_PWR1, "POWER1", TCPU_PWRX, "POWER2", -1, "Unknown" }, CompilerTypes[] = { TB_C, "C", TB_FORTRAN, "Fortran", TB_PASCAL, "Pascal", TB_ADA, "Ada", #ifdef TB_PLI TB_PLI, "PL/I", #endif #ifdef TB_PL1 TB_PL1, "PL/I", #endif TB_BASIC, "Basic", TB_LISP, "Lisp", TB_COBOL, "Cobol", TB_MODULA2, "Modula2", TB_CPLUSPLUS, "C++", TB_RPG, "RPG", TB_PL8, "PL8", TB_ASM, "Assembler", -1, "Unknown" }; const char *Type2String(unsigned short n, struct TypeNames TN[]) { int i; for (i = 0; TN[i].n != n && TN[i].n >= 0; i++); return TN[i].s; } int parse_coff(char *FName, int fd, long offset) { struct filehdr f_hdr; struct syment sym; union auxent aux; int file_found = 0, nsyms, naux; lseek(fd, offset, 0); if(read(fd, &f_hdr, sizeof (f_hdr)) != sizeof(f_hdr) || f_hdr.f_magic != 0x01df) { fprintf(stderr, "%s: not in XCOFF format\n", FName); return; } lseek(fd, f_hdr.f_symptr + offset, 0); for (nsyms = 0; nsyms < f_hdr.f_nsyms; nsyms++) { read(fd, &sym, SYMESZ); for (naux = 0; naux < sym.n_numaux; naux++, nsyms++) { read(fd, &aux, AUXESZ); if (sym.n_sclass == C_FILE && aux.x_file._x.x_ftype == XFT_FN) { file_found = 1; printf("%s(%s): %s:%s\n", FName, aux.x_file.x_fname, Type2String((sym.n_type >> 8) & 0xff, CompilerTypes), Type2String(sym.n_type & 0xff, CPUTypes)); } } } if (!file_found) { fprintf(stderr, "%s: no source file information found\n", FName); } } int decode_lib_subf(char *Fname, int fd, long subfile_offset, long *nextoffset, char **member_name_ptr) { int namelen; int member_length; char *name; struct ar_hdr hdr1; int bytes_read; lseek(fd, subfile_offset, 0); bytes_read = read(fd, &hdr1, sizeof(hdr1)); if (bytes_read == 0) return 0; /* end of archive, should not happen */ if (sizeof(hdr1) != bytes_read) { fprintf(stderr, "%s: malformed library archive\n", Fname); return 0; } if (sscanf(hdr1.ar_size, "%d", &member_length) != 1) { fprintf(stderr, "malformatted header of archive member (ar_size) in %s\n", Fname); return 0; } if (sscanf(hdr1.ar_namlen, "%d", &namelen) != 1) { fprintf(stderr, "malformatted header of archive member (ar_namlen) in %s\n", Fname); return 0; } if (sscanf(hdr1.ar_nxtmem, "%d", nextoffset) != 1) { fprintf(stderr, "malformatted header of archive member (ar_nxtmem) in %s\n", Fname); return 0; } name = (char *)malloc(namelen+1); strncpy (name, hdr1._ar_name.ar_name, namelen); if (read(fd, name + 2, namelen - 2) != namelen - 2) { fprintf(stderr, "malformatted header of archive member (name) in %s\n", Fname); return 0; } name[namelen] = 0; *member_name_ptr = name; return member_length; } int main(int argc, char *argv[]) { int fd, i, member_len; char *member, label[512]; long subfile_offset, lstmoff, nextoffset, coff_offset; FL_HDR filehdr; for(i=1; i (fd = open(argv[i], O_RDONLY))) { perror(argv[i]); } else { if (read(fd, &filehdr, FL_HSZ) == FL_HSZ && strncmp(filehdr.fl_magic, AIAMAG, SAIAMAG) == 0) { /* library */ nextoffset = atoi(filehdr.fl_fstmoff); lstmoff = atoi(filehdr.fl_lstmoff); if (nextoffset != 0) while (subfile_offset != lstmoff) { subfile_offset = nextoffset; if ((member_len = decode_lib_subf(argv[i], fd, subfile_offset, &nextoffset, &member) <= 0)) break; coff_offset = subfile_offset + AR_HSZ + strlen(member); if (coff_offset & 1) coff_offset++; strncpy(label, argv[i], 250); strcat(label, "->"); strncat(label, member, 255); parse_coff(label, fd, coff_offset); } } else { parse_coff(argv[i], fd, 0L); } close(fd); } } return 0; }