1 /*
2 * winDumpExts.c --
3 * Author: Gordon Chaffee, Scott Stanton
4 *
5 * History: The real functionality of this file was written by
6 * Matt Pietrek in 1993 in his pedump utility. I've
7 * modified it to dump the externals in a bunch of object
8 * files to create a .def file.
9 *
10 * 10/12/95 Modified by Scott Stanton to support Relocatable Object Module
11 * Format files for Borland C++ 4.5.
12 *
13 * Notes: Visual C++ puts an underscore before each exported symbol.
14 * This file removes them. I don't know if this is a problem
15 * this other compilers. If _MSC_VER is defined,
16 * the underscore is removed. If not, it isn't. To get a
17 * full dump of an object file, use the -f option. This can
18 * help determine the something that may be different with a
19 * compiler other than Visual C++.
20 *----------------------------------------------------------------------
21 *
22 */
23
24 #include <windows.h>
25 #include <stdio.h>
26 #include <string.h>
27 #include <process.h>
28
29 #ifdef _ALPHA_
30 #define e_magic_number IMAGE_FILE_MACHINE_ALPHA
31 #else
32 #define e_magic_number IMAGE_FILE_MACHINE_I386
33 #endif
34
35 /*
36 *----------------------------------------------------------------------
37 * GetArgcArgv --
38 *
39 * Break up a line into argc argv
40 *----------------------------------------------------------------------
41 */
42 int
GetArgcArgv(char * s,char ** argv)43 GetArgcArgv(char *s, char **argv)
44 {
45 int quote = 0;
46 int argc = 0;
47 char *bp;
48
49 bp = s;
50 while (1) {
51 while (isspace(*bp)) {
52 bp++;
53 }
54 if (*bp == '\n' || *bp == '\0') {
55 *bp = '\0';
56 return argc;
57 }
58 if (*bp == '\"') {
59 quote = 1;
60 bp++;
61 }
62 argv[argc++] = bp;
63
64 while (*bp != '\0') {
65 if (quote) {
66 if (*bp == '\"') {
67 quote = 0;
68 *bp = '\0';
69 bp++;
70 break;
71 }
72 bp++;
73 continue;
74 }
75 if (isspace(*bp)) {
76 *bp = '\0';
77 bp++;
78 break;
79 }
80 bp++;
81 }
82 }
83 }
84
85 /*
86 * The names of the first group of possible symbol table storage classes
87 */
88 char * SzStorageClass1[] = {
89 "NULL","AUTOMATIC","EXTERNAL","STATIC","REGISTER","EXTERNAL_DEF","LABEL",
90 "UNDEFINED_LABEL","MEMBER_OF_STRUCT","ARGUMENT","STRUCT_TAG",
91 "MEMBER_OF_UNION","UNION_TAG","TYPE_DEFINITION","UNDEFINED_STATIC",
92 "ENUM_TAG","MEMBER_OF_ENUM","REGISTER_PARAM","BIT_FIELD"
93 };
94
95 /*
96 * The names of the second group of possible symbol table storage classes
97 */
98 char * SzStorageClass2[] = {
99 "BLOCK","FUNCTION","END_OF_STRUCT","FILE","SECTION","WEAK_EXTERNAL"
100 };
101
102 /*
103 *----------------------------------------------------------------------
104 * GetSZStorageClass --
105 *
106 * Given a symbol storage class value, return a descriptive
107 * ASCII string
108 *----------------------------------------------------------------------
109 */
110 PSTR
GetSZStorageClass(BYTE storageClass)111 GetSZStorageClass(BYTE storageClass)
112 {
113 if ( storageClass <= IMAGE_SYM_CLASS_BIT_FIELD )
114 return SzStorageClass1[storageClass];
115 else if ( (storageClass >= IMAGE_SYM_CLASS_BLOCK)
116 && (storageClass <= IMAGE_SYM_CLASS_WEAK_EXTERNAL) )
117 return SzStorageClass2[storageClass-IMAGE_SYM_CLASS_BLOCK];
118 else
119 return "???";
120 }
121
122 /*
123 *----------------------------------------------------------------------
124 * GetSectionName --
125 *
126 * Used by DumpSymbolTable, it gives meaningful names to
127 * the non-normal section number.
128 *
129 * Results:
130 * A name is returned in buffer
131 *----------------------------------------------------------------------
132 */
133 void
GetSectionName(WORD section,PSTR buffer,unsigned cbBuffer)134 GetSectionName(WORD section, PSTR buffer, unsigned cbBuffer)
135 {
136 char tempbuffer[10];
137
138 switch ( (SHORT)section )
139 {
140 case IMAGE_SYM_UNDEFINED: strcpy(tempbuffer, "UNDEF"); break;
141 case IMAGE_SYM_ABSOLUTE: strcpy(tempbuffer, "ABS "); break;
142 case IMAGE_SYM_DEBUG: strcpy(tempbuffer, "DEBUG"); break;
143 default: wsprintf(tempbuffer, "%-5X", section);
144 }
145
146 strncpy(buffer, tempbuffer, cbBuffer-1);
147 }
148
149 /*
150 *----------------------------------------------------------------------
151 * DumpSymbolTable --
152 *
153 * Dumps a COFF symbol table from an EXE or OBJ. We only use
154 * it to dump tables from OBJs.
155 *----------------------------------------------------------------------
156 */
157 void
DumpSymbolTable(PIMAGE_SYMBOL pSymbolTable,FILE * fout,unsigned cSymbols)158 DumpSymbolTable(PIMAGE_SYMBOL pSymbolTable, FILE *fout, unsigned cSymbols)
159 {
160 unsigned i;
161 PSTR stringTable;
162 char sectionName[10];
163
164 fprintf(fout, "Symbol Table - %X entries (* = auxillary symbol)\n",
165 cSymbols);
166
167 fprintf(fout,
168 "Indx Name Value Section cAux Type Storage\n"
169 "---- -------------------- -------- ---------- ----- ------- --------\n");
170
171 /*
172 * The string table apparently starts right after the symbol table
173 */
174 stringTable = (PSTR)&pSymbolTable[cSymbols];
175
176 for ( i=0; i < cSymbols; i++ ) {
177 fprintf(fout, "%04X ", i);
178 if ( pSymbolTable->N.Name.Short != 0 )
179 fprintf(fout, "%-20.8s", pSymbolTable->N.ShortName);
180 else
181 fprintf(fout, "%-20s", stringTable + pSymbolTable->N.Name.Long);
182
183 fprintf(fout, " %08X", pSymbolTable->Value);
184
185 GetSectionName(pSymbolTable->SectionNumber, sectionName,
186 sizeof(sectionName));
187 fprintf(fout, " sect:%s aux:%X type:%02X st:%s\n",
188 sectionName,
189 pSymbolTable->NumberOfAuxSymbols,
190 pSymbolTable->Type,
191 GetSZStorageClass(pSymbolTable->StorageClass) );
192 #if 0
193 if ( pSymbolTable->NumberOfAuxSymbols )
194 DumpAuxSymbols(pSymbolTable);
195 #endif
196
197 /*
198 * Take into account any aux symbols
199 */
200 i += pSymbolTable->NumberOfAuxSymbols;
201 pSymbolTable += pSymbolTable->NumberOfAuxSymbols;
202 pSymbolTable++;
203 }
204 }
205
206 /*
207 *----------------------------------------------------------------------
208 * DumpExternals --
209 *
210 * Dumps a COFF symbol table from an EXE or OBJ. We only use
211 * it to dump tables from OBJs.
212 *----------------------------------------------------------------------
213 */
214 void
DumpExternals(PIMAGE_SYMBOL pSymbolTable,FILE * fout,unsigned cSymbols)215 DumpExternals(PIMAGE_SYMBOL pSymbolTable, FILE *fout, unsigned cSymbols)
216 {
217 unsigned i;
218 PSTR stringTable;
219 char *s, *f;
220 char symbol[1024];
221
222 /*
223 * The string table apparently starts right after the symbol table
224 */
225 stringTable = (PSTR)&pSymbolTable[cSymbols];
226
227 for ( i=0; i < cSymbols; i++ ) {
228 if (pSymbolTable->SectionNumber > 0 && pSymbolTable->Type == 0x20) {
229 if (pSymbolTable->StorageClass == IMAGE_SYM_CLASS_EXTERNAL) {
230 if (pSymbolTable->N.Name.Short != 0) {
231 strncpy(symbol, pSymbolTable->N.ShortName, 8);
232 symbol[8] = 0;
233 } else {
234 s = stringTable + pSymbolTable->N.Name.Long;
235 strcpy(symbol, s);
236 }
237 s = symbol;
238 f = strchr(s, '@');
239 if (f) {
240 *f = 0;
241 }
242 #if defined(_MSC_VER) && defined(_X86_)
243 if (symbol[0] == '_') {
244 s = &symbol[1];
245 }
246 #endif
247 if ((stricmp(s, "DllEntryPoint") != 0)
248 && (stricmp(s, "DllMain") != 0)) {
249 fprintf(fout, "\t%s\n", s);
250 }
251 }
252 }
253
254 /*
255 * Take into account any aux symbols
256 */
257 i += pSymbolTable->NumberOfAuxSymbols;
258 pSymbolTable += pSymbolTable->NumberOfAuxSymbols;
259 pSymbolTable++;
260 }
261 }
262
263 /*
264 *----------------------------------------------------------------------
265 * DumpObjFile --
266 *
267 * Dump an object file--either a full listing or just the exported
268 * symbols.
269 *----------------------------------------------------------------------
270 */
271 void
DumpObjFile(PIMAGE_FILE_HEADER pImageFileHeader,FILE * fout,int full)272 DumpObjFile(PIMAGE_FILE_HEADER pImageFileHeader, FILE *fout, int full)
273 {
274 PIMAGE_SYMBOL PCOFFSymbolTable;
275 DWORD COFFSymbolCount;
276
277 PCOFFSymbolTable = (PIMAGE_SYMBOL)
278 ((DWORD)pImageFileHeader + pImageFileHeader->PointerToSymbolTable);
279 COFFSymbolCount = pImageFileHeader->NumberOfSymbols;
280
281 if (full) {
282 DumpSymbolTable(PCOFFSymbolTable, fout, COFFSymbolCount);
283 } else {
284 DumpExternals(PCOFFSymbolTable, fout, COFFSymbolCount);
285 }
286 }
287
288 /*
289 *----------------------------------------------------------------------
290 * SkipToNextRecord --
291 *
292 * Skip over the current ROMF record and return the type of the
293 * next record.
294 *----------------------------------------------------------------------
295 */
296
297 BYTE
SkipToNextRecord(BYTE ** ppBuffer)298 SkipToNextRecord(BYTE **ppBuffer)
299 {
300 int length;
301 (*ppBuffer)++; /* Skip over the type.*/
302 length = *((WORD*)(*ppBuffer))++; /* Retrieve the length. */
303 *ppBuffer += length; /* Skip over the rest. */
304 return **ppBuffer; /* Return the type. */
305 }
306
307 /*
308 *----------------------------------------------------------------------
309 * DumpROMFObjFile --
310 *
311 * Dump a Relocatable Object Module Format file, displaying only
312 * the exported symbols.
313 *----------------------------------------------------------------------
314 */
315 void
DumpROMFObjFile(LPVOID pBuffer,FILE * fout)316 DumpROMFObjFile(LPVOID pBuffer, FILE *fout)
317 {
318 BYTE type, length;
319 char symbol[1024], *s;
320
321 while (1) {
322 type = SkipToNextRecord(&(BYTE*)pBuffer);
323 if (type == 0x90) { /* PUBDEF */
324 if (((BYTE*)pBuffer)[4] != 0) {
325 length = ((BYTE*)pBuffer)[5];
326 strncpy(symbol, ((char*)pBuffer) + 6, length);
327 symbol[length] = '\0';
328 s = symbol;
329 if ((stricmp(s, "DllEntryPoint") != 0)
330 && (stricmp(s, "DllMain") != 0)) {
331 if (s[0] == '_') {
332 s++;
333 fprintf(fout, "\t_%s\n\t%s=_%s\n", s, s, s);
334 } else {
335 fprintf(fout, "\t%s\n", s);
336 }
337 }
338 }
339 } else if (type == 0x8B || type == 0x8A) { /* MODEND */
340 break;
341 }
342 }
343 }
344
345 /*
346 *----------------------------------------------------------------------
347 * DumpFile --
348 *
349 * Open up a file, memory map it, and call the appropriate
350 * dumping routine
351 *----------------------------------------------------------------------
352 */
353 void
DumpFile(LPSTR filename,FILE * fout,int full)354 DumpFile(LPSTR filename, FILE *fout, int full)
355 {
356 HANDLE hFile;
357 HANDLE hFileMapping;
358 LPVOID lpFileBase;
359 PIMAGE_DOS_HEADER dosHeader;
360
361 hFile = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ, NULL,
362 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
363
364 if (hFile == INVALID_HANDLE_VALUE) {
365 fprintf(stderr, "Couldn't open file with CreateFile()\n");
366 return;
367 }
368
369 hFileMapping = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
370 if (hFileMapping == 0) {
371 CloseHandle(hFile);
372 fprintf(stderr, "Couldn't open file mapping with CreateFileMapping()\n");
373 return;
374 }
375
376 lpFileBase = MapViewOfFile(hFileMapping, FILE_MAP_READ, 0, 0, 0);
377 if (lpFileBase == 0) {
378 CloseHandle(hFileMapping);
379 CloseHandle(hFile);
380 fprintf(stderr, "Couldn't map view of file with MapViewOfFile()\n");
381 return;
382 }
383
384 dosHeader = (PIMAGE_DOS_HEADER)lpFileBase;
385 if (dosHeader->e_magic == IMAGE_DOS_SIGNATURE) {
386 #if 0
387 DumpExeFile( dosHeader );
388 #else
389 fprintf(stderr, "File is an executable. I don't dump those.\n");
390 return;
391 #endif
392 }
393 /* Does it look like a i386 COFF OBJ file??? */
394 else if ((dosHeader->e_magic == e_magic_number)
395 && (dosHeader->e_sp == 0)) {
396 /*
397 * The two tests above aren't what they look like. They're
398 * really checking for IMAGE_FILE_HEADER.Machine == i386 (0x14C)
399 * and IMAGE_FILE_HEADER.SizeOfOptionalHeader == 0;
400 */
401 DumpObjFile((PIMAGE_FILE_HEADER) lpFileBase, fout, full);
402 } else if (*((BYTE *)lpFileBase) == 0x80) {
403 /*
404 * This file looks like it might be a ROMF file.
405 */
406 DumpROMFObjFile(lpFileBase, fout);
407 } else {
408 printf("unrecognized file format\n");
409 }
410 UnmapViewOfFile(lpFileBase);
411 CloseHandle(hFileMapping);
412 CloseHandle(hFile);
413 }
414
415 void
main(int argc,char ** argv)416 main(int argc, char **argv)
417 {
418 char *fargv[1000];
419 char cmdline[10000];
420 int i, arg;
421 FILE *fout;
422 int pos;
423 int full = 0;
424 char *outfile = NULL;
425
426 if (argc < 3) {
427 Usage:
428 fprintf(stderr, "Usage: %s ?-o outfile? ?-f(ull)? <dllname> <object filenames> ..\n", argv[0]);
429 exit(1);
430 }
431
432 arg = 1;
433 while (argv[arg][0] == '-') {
434 if (strcmp(argv[arg], "--") == 0) {
435 arg++;
436 break;
437 } else if (strcmp(argv[arg], "-f") == 0) {
438 full = 1;
439 } else if (strcmp(argv[arg], "-o") == 0) {
440 arg++;
441 if (arg == argc) {
442 goto Usage;
443 }
444 outfile = argv[arg];
445 }
446 arg++;
447 }
448 if (arg == argc) {
449 goto Usage;
450 }
451
452 if (outfile) {
453 fout = fopen(outfile, "w+");
454 if (fout == NULL) {
455 fprintf(stderr, "Unable to open \'%s\' for writing:\n",
456 argv[arg]);
457 perror("");
458 exit(1);
459 }
460 } else {
461 fout = stdout;
462 }
463
464 if (! full) {
465 char *dllname = argv[arg];
466 arg++;
467 if (arg == argc) {
468 goto Usage;
469 }
470 fprintf(fout, "LIBRARY %s\n", dllname);
471 fprintf(fout, "EXETYPE WINDOWS\n");
472 fprintf(fout, "CODE PRELOAD MOVEABLE DISCARDABLE\n");
473 fprintf(fout, "DATA PRELOAD MOVEABLE MULTIPLE\n\n");
474 fprintf(fout, "EXPORTS\n");
475 }
476
477 for (; arg < argc; arg++) {
478 if (argv[arg][0] == '@') {
479 FILE *fargs = fopen(&argv[arg][1], "r");
480 if (fargs == NULL) {
481 fprintf(stderr, "Unable to open \'%s\' for reading:\n",
482 argv[arg]);
483 perror("");
484 exit(1);
485 }
486 pos = 0;
487 for (i = 0; i < arg; i++) {
488 strcpy(&cmdline[pos], argv[i]);
489 pos += strlen(&cmdline[pos]) + 1;
490 fargv[i] = argv[i];
491 }
492 fgets(&cmdline[pos], sizeof(cmdline), fargs);
493 fprintf(stderr, "%s\n", &cmdline[pos]);
494 fclose(fargs);
495 i += GetArgcArgv(&cmdline[pos], &fargv[i]);
496 argc = i;
497 argv = fargv;
498 }
499 DumpFile(argv[arg], fout, full);
500 }
501 exit(0);
502 }
503