/* objtype.c Copyright (C) 2005-2007 Codemist Ltd */ /* * This code may be used and modified, and redistributed in binary * or source form, subject to the "CCL Public License", which should * accompany it. This license is a variant on the BSD license, and thus * permits use of code derived from this in either open and commercial * projects: but it does require that updates to this code be made * available back to the originators of the package. * Before merging other code in with this or linking this code * with other packages or libraries please check that the license terms * of the other material are compatible with those of this. */ /* Signature: 73591169 07-Apr-2007 */ /* * Decodes the type of an object file and generates a small source * file that gives information about it and that can also be used to * give information about a compiler command. Typical usage: * objtype foo.o imports.def - $CC $CFLAGS */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include /* * In some cases I may end up passing a file-name of the form * /cygdrive/d/path.../leaf * here. For things to behave I need to map that onto * d:/...path/leaf */ static FILE *myfopen(char *name, char *mode) { char newname[256]; if (strncmp(name, "/cygdrive/", 10) != 0) return fopen(name, mode); newname[0] = name[10]; newname[1] = ':'; strcpy(&newname[2], &name[11]); return fopen(newname, mode); } int main(int argc, char *argv[]) { FILE *f1, *f2, *f3; time_t t = time(NULL); unsigned char hdr[20]; int sixtyFourBit = 0, byteOrder = 0, machine = 0; char *s = NULL; int i; if (argc < 4) { fprintf(stderr, "Usage: objtype xx.obj imports.def dest.c $CC $CFLAGS\n"); return 1; } if (strcmp(argv[1], "-") == 0) f1 = stdin; else f1 = myfopen(argv[1], "rb"); if (f1 == NULL) { fprintf(stderr, "File \"%s\" not found\n", argv[1]); return 1; } if (strcmp(argv[2], "-") == 0) f2 = stdin; else f2 = myfopen(argv[2], "r"); if (f2 == NULL) { fprintf(stderr, "File \"%s\" not found\n", argv[2]); fclose(f1); return 1; } if (strcmp(argv[3], "-") == 0) f3 = stdout; else f3 = myfopen(argv[3], "w"); if (f3 == NULL) { fprintf(stderr, "File \"%s\" can not be written to\n", argv[3]); fclose(f1); fclose(f2); return 1; } if (fread(hdr, 20, 1, f1) != 1) { fprintf(stderr, "Unable to read header from input file\n"); fclose(f1); fclose(f2); fclose(f3); return 1; } fprintf(f3, "/*\n * Created %s */\n\n", asctime(localtime(&t))); fprintf(f3, "\nchar *linker_type = \""); if (hdr[0] == 0xfe && hdr[1] == 0xed && hdr[2] == 0xfa && hdr[3] == 0xce) fprintf(f3, "mac-darwin"); else if (hdr[0] == 0x7f && hdr[1] == 'E' && hdr[2] == 'L' && hdr[3] == 'F') /* ELF-format file */ { switch (hdr[4]) { case 1: /* 32-bit ELF */ sixtyFourBit = 0; break; case 2: /* 64-bit ELF */ sixtyFourBit = 1; break; default: goto invalidObjectFormat; } /* hdr[5] is 1 for LSB, 2 for MSB data format */ if (hdr[5] == 0 || hdr[5] > 2) goto invalidObjectFormat; byteOrder = hdr[5] - 1; /* hdr[6] had BETTER be 1, for "current ELT version" */ if (hdr[6] != 1) goto invalidObjectFormat; /* hdr[7] & hdr[8] ought to be 0 to indicate "ordinary" ELF. */ /* (hdr[7] can be 1 for HP Unix?) */ if (byteOrder == 0) machine = hdr[18] | (hdr[19]<<8); else machine = (hdr[18]<<8) | hdr[19]; /* * A few sample machine types... * 386 3 * ppc 20 * ppc64 21 * arm 40 * x86_64 62 * I will detect and name those ones explicitly */ switch (machine) { case 3: if (!sixtyFourBit && byteOrder == 0) s = "i386"; break; case 20:if (!sixtyFourBit) s = "ppc"; break; case 21:if (sixtyFourBit) s = "ppc64"; break; case 62:if (sixtyFourBit) s = "x86_64"; break; } if (s != NULL) fprintf(f3, "%s", s); else fprintf(f3, "ELF-%d-%d", 2*sixtyFourBit+byteOrder, machine); } else { /* * If the file is not ELF I will suppose that it is COFF, and * in that case the first two bytes identify a machine-type. Notable values * are * 386 0x14c * arm 0x1c0 * x86_64 0x8664 note that these are given LSB * This format is what is used by Windows. */ machine = hdr[0] + (hdr[1]<<8); switch (machine) { case 0x14c: fprintf(f3, "win32"); break; case 0x1c0: fprintf(f3, "arm-coff"); break; case 0x8664:fprintf(f3, "win64"); break; default: /* eg Itanium Windows could hit this case, I guess */ fprintf(f3, "COFF-%x", hdr[0] | (hdr[1]<<8)); break; } } fprintf(f3, "\";\n\nchar *import_data[] = {\n"); for (;;) { char line[100]; int ch = getc(f2); while (ch == '\r') ch = getc(f2); i = 0; while (ch != '\n' && ch != EOF) { if (i < 90) line[i++] = ch; ch = getc(f2); while (ch == '\r') ch = getc(f2); } line[i] = 0; if (i == 0) break; fprintf(f3, " \"%s\",\n", line); } fprintf(f3, " NULL\n};\n\nchar *compiler_command[] = {\n \"%s\"", argv[4]); for (i=5; i