Added partial VxD support.
[wine] / tools / winedump / pe.c
1 /*
2  *      PE dumping utility
3  *
4  *      Copyright 2001 Eric Pouech
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include "config.h"
22 #include "wine/port.h"
23
24 #include <stdlib.h>
25 #include <stdarg.h>
26 #include <stdio.h>
27 #ifdef HAVE_UNISTD_H
28 # include <unistd.h>
29 #endif
30 #include <time.h>
31 #ifdef HAVE_SYS_TYPES_H
32 # include <sys/types.h>
33 #endif
34 #ifdef HAVE_SYS_STAT_H
35 # include <sys/stat.h>
36 #endif
37 #ifdef HAVE_SYS_MMAN_H
38 #include <sys/mman.h>
39 #endif
40 #include <fcntl.h>
41
42 #define NONAMELESSUNION
43 #define NONAMELESSSTRUCT
44 #include "windef.h"
45 #include "winbase.h"
46 #include "winedump.h"
47 #include "pe.h"
48
49 #ifndef O_BINARY
50 # define O_BINARY 0
51 #endif
52
53 void*                   PE_base;
54 unsigned long           PE_total_len;
55 IMAGE_NT_HEADERS*       PE_nt_headers;
56
57 enum FileSig {SIG_UNKNOWN, SIG_DOS, SIG_PE, SIG_DBG, SIG_NE, SIG_LE};
58
59 static inline unsigned int strlenW( const WCHAR *str )
60 {
61     const WCHAR *s = str;
62     while (*s) s++;
63     return s - str;
64 }
65
66 char*   get_time_str(DWORD _t)
67 {
68     time_t      t = (time_t)_t;
69     static char buf[128];
70
71     /* FIXME: I don't get the same values from MS' pedump running under Wine...
72      * I wonder if Wine isn't broken wrt to GMT settings...
73      */
74     strncpy(buf, ctime(&t), sizeof(buf));
75     buf[sizeof(buf) - 1] = '\0';
76     if (buf[strlen(buf)-1] == '\n')
77         buf[strlen(buf)-1] = '\0';
78     return buf;
79 }
80
81 static  const char* get_machine_str(DWORD mach)
82 {
83     switch (mach)
84     {
85     case IMAGE_FILE_MACHINE_UNKNOWN:    return "Unknown";
86     case IMAGE_FILE_MACHINE_I860:       return "i860";
87     case IMAGE_FILE_MACHINE_I386:       return "i386";
88     case IMAGE_FILE_MACHINE_R3000:      return "R3000";
89     case IMAGE_FILE_MACHINE_R4000:      return "R4000";
90     case IMAGE_FILE_MACHINE_R10000:     return "R10000";
91     case IMAGE_FILE_MACHINE_ALPHA:      return "Alpha";
92     case IMAGE_FILE_MACHINE_POWERPC:    return "PowerPC";
93     }
94     return "???";
95 }
96
97 void*   PRD(unsigned long prd, unsigned long len)
98 {
99     return (prd + len > PE_total_len) ? NULL : (char*)PE_base + prd;
100 }
101
102 unsigned long Offset(void* ptr)
103 {
104     if (ptr < PE_base) {printf("<<<<<ptr below\n");return 0;}
105     if ((char *)ptr >= (char*)PE_base + PE_total_len) {printf("<<<<<ptr above\n");return 0;}
106     return (char*)ptr - (char*)PE_base;
107 }
108
109 static void*    RVA(unsigned long rva, unsigned long len)
110 {
111     IMAGE_SECTION_HEADER*       sectHead;
112     int                         i;
113
114     if (rva == 0) return NULL;
115
116     sectHead = (IMAGE_SECTION_HEADER*)((char*)PE_nt_headers + sizeof(DWORD) +
117                                        sizeof(IMAGE_FILE_HEADER) +
118                                        PE_nt_headers->FileHeader.SizeOfOptionalHeader);
119
120     for (i = PE_nt_headers->FileHeader.NumberOfSections - 1; i >= 0; i--)
121     {
122         if (sectHead[i].VirtualAddress <= rva &&
123             rva + len <= (DWORD)sectHead[i].VirtualAddress + sectHead[i].SizeOfRawData)
124         {
125             /* return image import directory offset */
126             return PRD(sectHead[i].PointerToRawData + rva - sectHead[i].VirtualAddress, len);
127         }
128     }
129
130     return NULL;
131 }
132
133 static  void*   get_dir(unsigned idx)
134 {
135     if (idx >= PE_nt_headers->OptionalHeader.NumberOfRvaAndSizes)
136         return NULL;
137     return RVA(PE_nt_headers->OptionalHeader.DataDirectory[idx].VirtualAddress,
138                PE_nt_headers->OptionalHeader.DataDirectory[idx].Size);
139 }
140
141 static void *get_dir_and_size(unsigned int idx, unsigned int *size)
142 {
143     if (idx >= PE_nt_headers->OptionalHeader.NumberOfRvaAndSizes)
144         return NULL;
145     *size = PE_nt_headers->OptionalHeader.DataDirectory[idx].Size;
146     return RVA(PE_nt_headers->OptionalHeader.DataDirectory[idx].VirtualAddress, *size);
147 }
148
149 static const char*      DirectoryNames[16] = {
150     "EXPORT",           "IMPORT",       "RESOURCE",     "EXCEPTION",
151     "SECURITY",         "BASERELOC",    "DEBUG",        "ARCHITECTURE",
152     "GLOBALPTR",        "TLS",          "LOAD_CONFIG",  "Bound IAT",
153     "IAT",              "Delay IAT",    "COM Descript", ""
154 };
155
156 static  void    dump_pe_header(void)
157 {
158     char                        *str;
159     IMAGE_FILE_HEADER           *fileHeader;
160     IMAGE_OPTIONAL_HEADER       *optionalHeader;
161     unsigned                    i;
162
163     printf("File Header\n");
164     fileHeader = &PE_nt_headers->FileHeader;
165
166     printf("  Machine:                      %04X (%s)\n",
167            fileHeader->Machine, get_machine_str(fileHeader->Machine));
168     printf("  Number of Sections:           %d\n", fileHeader->NumberOfSections);
169     printf("  TimeDateStamp:                %08lX (%s) offset %lu\n",
170            fileHeader->TimeDateStamp, get_time_str(fileHeader->TimeDateStamp),
171            Offset(&(fileHeader->TimeDateStamp)));
172     printf("  PointerToSymbolTable:         %08lX\n", fileHeader->PointerToSymbolTable);
173     printf("  NumberOfSymbols:              %08lX\n", fileHeader->NumberOfSymbols);
174     printf("  SizeOfOptionalHeader:         %04X\n", fileHeader->SizeOfOptionalHeader);
175     printf("  Characteristics:              %04X\n", fileHeader->Characteristics);
176 #define X(f,s)  if (fileHeader->Characteristics & f) printf("    %s\n", s)
177     X(IMAGE_FILE_RELOCS_STRIPPED,       "RELOCS_STRIPPED");
178     X(IMAGE_FILE_EXECUTABLE_IMAGE,      "EXECUTABLE_IMAGE");
179     X(IMAGE_FILE_LINE_NUMS_STRIPPED,    "LINE_NUMS_STRIPPED");
180     X(IMAGE_FILE_LOCAL_SYMS_STRIPPED,   "LOCAL_SYMS_STRIPPED");
181     X(IMAGE_FILE_16BIT_MACHINE,         "16BIT_MACHINE");
182     X(IMAGE_FILE_BYTES_REVERSED_LO,     "BYTES_REVERSED_LO");
183     X(IMAGE_FILE_32BIT_MACHINE,         "32BIT_MACHINE");
184     X(IMAGE_FILE_DEBUG_STRIPPED,        "DEBUG_STRIPPED");
185     X(IMAGE_FILE_SYSTEM,                "SYSTEM");
186     X(IMAGE_FILE_DLL,                   "DLL");
187     X(IMAGE_FILE_BYTES_REVERSED_HI,     "BYTES_REVERSED_HI");
188 #undef X
189     printf("\n");
190
191     /* hope we have the right size */
192     printf("Optional Header\n");
193     optionalHeader = &PE_nt_headers->OptionalHeader;
194     printf("  Magic                              0x%-4X         %u\n",
195            optionalHeader->Magic, optionalHeader->Magic);
196     printf("  linker version                     %u.%02u\n",
197            optionalHeader->MajorLinkerVersion, optionalHeader->MinorLinkerVersion);
198     printf("  size of code                       0x%-8lx     %lu\n",
199            optionalHeader->SizeOfCode, optionalHeader->SizeOfCode);
200     printf("  size of initialized data           0x%-8lx     %lu\n",
201            optionalHeader->SizeOfInitializedData, optionalHeader->SizeOfInitializedData);
202     printf("  size of uninitialized data         0x%-8lx     %lu\n",
203            optionalHeader->SizeOfUninitializedData, optionalHeader->SizeOfUninitializedData);
204     printf("  entrypoint RVA                     0x%-8lx     %lu\n",
205            optionalHeader->AddressOfEntryPoint, optionalHeader->AddressOfEntryPoint);
206     printf("  base of code                       0x%-8lx     %lu\n",
207            optionalHeader->BaseOfCode, optionalHeader->BaseOfCode);
208     printf("  base of data                       0x%-8lX     %lu\n",
209            optionalHeader->BaseOfData, optionalHeader->BaseOfData);
210     printf("  image base                         0x%-8lX     %lu\n",
211            optionalHeader->ImageBase, optionalHeader->ImageBase);
212     printf("  section align                      0x%-8lx     %lu\n",
213            optionalHeader->SectionAlignment, optionalHeader->SectionAlignment);
214     printf("  file align                         0x%-8lx     %lu\n",
215            optionalHeader->FileAlignment, optionalHeader->FileAlignment);
216     printf("  required OS version                %u.%02u\n",
217            optionalHeader->MajorOperatingSystemVersion, optionalHeader->MinorOperatingSystemVersion);
218     printf("  image version                      %u.%02u\n",
219            optionalHeader->MajorImageVersion, optionalHeader->MinorImageVersion);
220     printf("  subsystem version                  %u.%02u\n",
221            optionalHeader->MajorSubsystemVersion, optionalHeader->MinorSubsystemVersion);
222     printf("  Win32 Version                      0x%lX\n", optionalHeader->Win32VersionValue);
223     printf("  size of image                      0x%-8lx     %lu\n",
224            optionalHeader->SizeOfImage, optionalHeader->SizeOfImage);
225     printf("  size of headers                    0x%-8lx     %lu\n",
226            optionalHeader->SizeOfHeaders, optionalHeader->SizeOfHeaders);
227     printf("  checksum                           0x%lX\n", optionalHeader->CheckSum);
228     switch (optionalHeader->Subsystem)
229     {
230     default:
231     case IMAGE_SUBSYSTEM_UNKNOWN:       str = "Unknown";        break;
232     case IMAGE_SUBSYSTEM_NATIVE:        str = "Native";         break;
233     case IMAGE_SUBSYSTEM_WINDOWS_GUI:   str = "Windows GUI";    break;
234     case IMAGE_SUBSYSTEM_WINDOWS_CUI:   str = "Windows CUI";    break;
235     case IMAGE_SUBSYSTEM_OS2_CUI:       str = "OS/2 CUI";       break;
236     case IMAGE_SUBSYSTEM_POSIX_CUI:     str = "Posix CUI";      break;
237     }
238     printf("  Subsystem                          0x%X (%s)\n", optionalHeader->Subsystem, str);
239     printf("  DLL flags                          0x%X\n", optionalHeader->DllCharacteristics);
240     printf("  stack reserve size                 0x%-8lx     %lu\n",
241            optionalHeader->SizeOfStackReserve, optionalHeader->SizeOfStackReserve);
242     printf("  stack commit size                  0x%-8lx     %lu\n",
243            optionalHeader->SizeOfStackCommit, optionalHeader->SizeOfStackCommit);
244     printf("  heap reserve size                  0x%-8lx     %lu\n",
245            optionalHeader->SizeOfHeapReserve, optionalHeader->SizeOfHeapReserve);
246     printf("  heap commit size                   0x%-8lx     %lu\n",
247            optionalHeader->SizeOfHeapCommit, optionalHeader->SizeOfHeapCommit);
248     printf("  loader flags                       0x%lX\n", optionalHeader->LoaderFlags);
249     printf("  RVAs & sizes                       0x%lX\n", optionalHeader->NumberOfRvaAndSizes);
250     printf("\n");
251
252     printf("Data Directory\n");
253     printf("%ld\n", optionalHeader->NumberOfRvaAndSizes * sizeof(IMAGE_DATA_DIRECTORY));
254
255     for (i = 0; i < optionalHeader->NumberOfRvaAndSizes && i < 16; i++)
256     {
257         printf("  %-12s rva: 0x%-8lX  size: %8lu\n",
258                DirectoryNames[i], optionalHeader->DataDirectory[i].VirtualAddress,
259                optionalHeader->DataDirectory[i].Size);
260     }
261     printf("\n");
262 }
263
264 static  void    dump_sections(void* addr, unsigned num_sect)
265 {
266     IMAGE_SECTION_HEADER*       sectHead = addr;
267     unsigned                    i;
268
269     printf("Section Table\n");
270     for (i = 0; i < num_sect; i++, sectHead++)
271     {
272         printf("  %02d %-8.8s   VirtSize: %-8lu  VirtAddr:  %-8lu 0x%08lx\n",
273                i + 1, sectHead->Name, sectHead->Misc.VirtualSize, sectHead->VirtualAddress,
274                sectHead->VirtualAddress);
275         printf("    raw data offs: %-8lu raw data size: %-8lu\n",
276                sectHead->PointerToRawData, sectHead->SizeOfRawData);
277         printf("    relocation offs: %-8lu  relocations:   %-8u\n",
278                sectHead->PointerToRelocations, sectHead->NumberOfRelocations);
279         printf("    line # offs:     %-8lu  line #'s:      %-8u\n",
280                sectHead->PointerToLinenumbers, sectHead->NumberOfLinenumbers);
281         printf("    characteristics: 0x%08lx\n", sectHead->Characteristics);
282         printf("      ");
283 #define X(b,s)  if (sectHead->Characteristics & b) printf(s "  ")
284 /* #define IMAGE_SCN_TYPE_REG                   0x00000000 - Reserved */
285 /* #define IMAGE_SCN_TYPE_DSECT                 0x00000001 - Reserved */
286 /* #define IMAGE_SCN_TYPE_NOLOAD                0x00000002 - Reserved */
287 /* #define IMAGE_SCN_TYPE_GROUP                 0x00000004 - Reserved */
288 /* #define IMAGE_SCN_TYPE_NO_PAD                0x00000008 - Reserved */
289 /* #define IMAGE_SCN_TYPE_COPY                  0x00000010 - Reserved */
290
291         X(IMAGE_SCN_CNT_CODE,                   "CODE");
292         X(IMAGE_SCN_CNT_INITIALIZED_DATA,       "INITIALIZED_DATA");
293         X(IMAGE_SCN_CNT_UNINITIALIZED_DATA,     "UNINITIALIZED_DATA");
294
295         X(IMAGE_SCN_LNK_OTHER,                  "LNK_OTHER");
296         X(IMAGE_SCN_LNK_INFO,                   "LNK_INFO");
297 /* #define      IMAGE_SCN_TYPE_OVER             0x00000400 - Reserved */
298         X(IMAGE_SCN_LNK_REMOVE,                 "LNK_REMOVE");
299         X(IMAGE_SCN_LNK_COMDAT,                 "LNK_COMDAT");
300
301 /*                                              0x00002000 - Reserved */
302 /* #define IMAGE_SCN_MEM_PROTECTED              0x00004000 - Obsolete */
303         X(IMAGE_SCN_MEM_FARDATA,                "MEM_FARDATA");
304
305 /* #define IMAGE_SCN_MEM_SYSHEAP                0x00010000 - Obsolete */
306         X(IMAGE_SCN_MEM_PURGEABLE,              "MEM_PURGEABLE");
307         X(IMAGE_SCN_MEM_16BIT,                  "MEM_16BIT");
308         X(IMAGE_SCN_MEM_LOCKED,                 "MEM_LOCKED");
309         X(IMAGE_SCN_MEM_PRELOAD,                "MEM_PRELOAD");
310
311         X(IMAGE_SCN_ALIGN_1BYTES,               "ALIGN_1BYTES");
312         X(IMAGE_SCN_ALIGN_2BYTES,               "ALIGN_2BYTES");
313         X(IMAGE_SCN_ALIGN_4BYTES,               "ALIGN_4BYTES");
314         X(IMAGE_SCN_ALIGN_8BYTES,               "ALIGN_8BYTES");
315         X(IMAGE_SCN_ALIGN_16BYTES,              "ALIGN_16BYTES");
316         X(IMAGE_SCN_ALIGN_32BYTES,              "ALIGN_32BYTES");
317         X(IMAGE_SCN_ALIGN_64BYTES,              "ALIGN_64BYTES");
318 /*                                              0x00800000 - Unused */
319
320         X(IMAGE_SCN_LNK_NRELOC_OVFL,            "LNK_NRELOC_OVFL");
321
322         X(IMAGE_SCN_MEM_DISCARDABLE,            "MEM_DISCARDABLE");
323         X(IMAGE_SCN_MEM_NOT_CACHED,             "MEM_NOT_CACHED");
324         X(IMAGE_SCN_MEM_NOT_PAGED,              "MEM_NOT_PAGED");
325         X(IMAGE_SCN_MEM_SHARED,                 "MEM_SHARED");
326         X(IMAGE_SCN_MEM_EXECUTE,                "MEM_EXECUTE");
327         X(IMAGE_SCN_MEM_READ,                   "MEM_READ");
328         X(IMAGE_SCN_MEM_WRITE,                  "MEM_WRITE");
329 #undef X
330         printf("\n\n");
331     }
332     printf("\n");
333 }
334
335 static  void    dump_dir_exported_functions(void)
336 {
337     unsigned int size;
338     IMAGE_EXPORT_DIRECTORY      *exportDir = get_dir_and_size(IMAGE_FILE_EXPORT_DIRECTORY, &size);
339     unsigned int                i;
340     DWORD*                      pFunc;
341     DWORD*                      pName;
342     WORD*                       pOrdl;
343     DWORD*                      map;
344     parsed_symbol               symbol;
345
346     if (!exportDir) return;
347
348     printf("Exports table:\n");
349     printf("\n");
350     printf("  Name:            %s\n", (char*)RVA(exportDir->Name, sizeof(DWORD)));
351     printf("  Characteristics: %08lx\n", exportDir->Characteristics);
352     printf("  TimeDateStamp:   %08lX %s\n",
353            exportDir->TimeDateStamp, get_time_str(exportDir->TimeDateStamp));
354     printf("  Version:         %u.%02u\n", exportDir->MajorVersion, exportDir->MinorVersion);
355     printf("  Ordinal base:    %lu\n", exportDir->Base);
356     printf("  # of functions:  %lu\n", exportDir->NumberOfFunctions);
357     printf("  # of Names:      %lu\n", exportDir->NumberOfNames);
358     printf("Adresses of functions: %08lX\n", exportDir->AddressOfFunctions);
359     printf("Adresses of name ordinals: %08lX\n", exportDir->AddressOfNameOrdinals);
360     printf("Adresses of names: %08lX\n", exportDir->AddressOfNames);
361     printf("\n");
362     printf("  Entry Pt  Ordn  Name\n");
363
364     pFunc = RVA(exportDir->AddressOfFunctions, exportDir->NumberOfFunctions * sizeof(DWORD));
365     if (!pFunc) {printf("Can't grab functions' address table\n"); return;}
366     pName = RVA(exportDir->AddressOfNames, exportDir->NumberOfNames * sizeof(DWORD));
367     if (!pName) {printf("Can't grab functions' name table\n"); return;}
368     pOrdl = RVA(exportDir->AddressOfNameOrdinals, exportDir->NumberOfNames * sizeof(WORD));
369     if (!pOrdl) {printf("Can't grab functions' ordinal table\n"); return;}
370
371     /* bit map of used funcs */
372     map = calloc(((exportDir->NumberOfFunctions + 31) & ~31) / 32, sizeof(DWORD));
373     if (!map) fatal("no memory");
374
375     for (i = 0; i < exportDir->NumberOfNames; i++, pName++, pOrdl++)
376     {
377         char*   name;
378
379         map[*pOrdl / 32] |= 1 << (*pOrdl % 32);
380
381         name = (char*)RVA(*pName, sizeof(DWORD));
382         if (name && globals.do_demangle)
383         {
384             printf("  %08lX  %4lu ", pFunc[*pOrdl], exportDir->Base + *pOrdl);
385
386             symbol_init(&symbol, name);
387             if (symbol_demangle(&symbol) == -1)
388                 printf(name);
389             else if (symbol.flags & SYM_DATA)
390                 printf(symbol.arg_text[0]);
391             else
392                 output_prototype(stdout, &symbol);
393             symbol_clear(&symbol);
394         }
395         else
396         {
397             printf("  %08lX  %4lu %s", pFunc[*pOrdl], exportDir->Base + *pOrdl, name);
398         }
399         /* check for forwarded function */
400         if ((char *)RVA(pFunc[*pOrdl],sizeof(void*)) >= (char *)exportDir &&
401             (char *)RVA(pFunc[*pOrdl],sizeof(void*)) < (char *)exportDir + size)
402             printf( " (-> %s)", (char *)RVA(pFunc[*pOrdl],1));
403         printf("\n");
404     }
405     pFunc = RVA(exportDir->AddressOfFunctions, exportDir->NumberOfFunctions * sizeof(DWORD));
406     if (!pFunc) {printf("Can't grab functions' address table\n"); return;}
407     for (i = 0; i < exportDir->NumberOfFunctions; i++)
408     {
409         if (pFunc[i] && !(map[i / 32] & (1 << (i % 32))))
410         {
411             printf("  %08lX  %4lu <by ordinal>\n", pFunc[i], exportDir->Base + i);
412         }
413     }
414     free(map);
415     printf("\n");
416 }
417
418 static  void    dump_dir_imported_functions(void)
419 {
420     IMAGE_IMPORT_DESCRIPTOR     *importDesc = get_dir(IMAGE_FILE_IMPORT_DIRECTORY);
421     unsigned                    nb_imp, i;
422
423     if (!importDesc)    return;
424     nb_imp = PE_nt_headers->OptionalHeader.DataDirectory[IMAGE_FILE_IMPORT_DIRECTORY].Size /
425         sizeof(*importDesc);
426     if (!nb_imp) return;
427
428     printf("Import Table size: %lu\n",
429            PE_nt_headers->OptionalHeader.DataDirectory[IMAGE_FILE_IMPORT_DIRECTORY].Size);/* FIXME */
430
431     for (i = 0; i < nb_imp - 1; i++) /* the last descr is set as 0 as a sentinel */
432     {
433         IMAGE_THUNK_DATA*       il;
434         IMAGE_IMPORT_BY_NAME*   iibn;
435
436         if (!importDesc->Name ||
437             (importDesc->u.OriginalFirstThunk == NULL && importDesc->FirstThunk == NULL))
438         {
439             /* FIXME */
440             printf("<<<<<<<null entry\n");
441             break;
442         }
443         printf("  offset %lu %s\n", Offset(importDesc), (char*)RVA(importDesc->Name, sizeof(DWORD)));
444         printf("  Hint/Name Table: %08lX\n", (DWORD)importDesc->u.OriginalFirstThunk);
445         printf("  TimeDataStamp:   %08lX (%s)\n",
446                importDesc->TimeDateStamp, get_time_str(importDesc->TimeDateStamp));
447         printf("  ForwarderChain:  %08lX\n", importDesc->ForwarderChain);
448         printf("  First thunk RVA: %08lX (delta: %u 0x%x)\n",
449                (DWORD)importDesc->FirstThunk, -1, -1); /* FIXME */
450
451         printf("  Ordn  Name\n");
452
453         il = (importDesc->u.OriginalFirstThunk != 0) ?
454             RVA((DWORD)importDesc->u.OriginalFirstThunk, sizeof(DWORD)) :
455             RVA((DWORD)importDesc->FirstThunk, sizeof(DWORD));
456
457         if (!il) {printf("Can't grab thunk data, going to next imported DLL\n"); continue;}
458
459         for (; il->u1.Ordinal; il++)
460         {
461             if (IMAGE_SNAP_BY_ORDINAL(il->u1.Ordinal))
462             {
463                 printf("  %4lu  <by ordinal>\n", IMAGE_ORDINAL(il->u1.Ordinal));
464             }
465             else
466             {
467                 iibn = RVA((DWORD)il->u1.AddressOfData, sizeof(DWORD));
468                 if (!il)
469                 {
470                     printf("Can't grab import by name info, skipping to next ordinal\n");
471                 }
472                 else
473                 {
474                     printf("  %4u  %s %lx\n", iibn->Hint, iibn->Name, (DWORD)il->u1.AddressOfData);
475                 }
476             }
477         }
478         printf("\n");
479         importDesc++;
480     }
481     printf("\n");
482 }
483
484 static  void    dump_dir_debug_dir(IMAGE_DEBUG_DIRECTORY* idd, int idx)
485 {
486     const       char*   str;
487
488     printf("Directory %02u\n", idx + 1);
489     printf("  Characteristics:   %08lX\n", idd->Characteristics);
490     printf("  TimeDateStamp:     %08lX %s\n",
491            idd->TimeDateStamp, get_time_str(idd->TimeDateStamp));
492     printf("  Version            %u.%02u\n", idd->MajorVersion, idd->MinorVersion);
493     switch (idd->Type)
494     {
495     default:
496     case IMAGE_DEBUG_TYPE_UNKNOWN:      str = "UNKNOWN";        break;
497     case IMAGE_DEBUG_TYPE_COFF:         str = "COFF";           break;
498     case IMAGE_DEBUG_TYPE_CODEVIEW:     str = "CODEVIEW";       break;
499     case IMAGE_DEBUG_TYPE_FPO:          str = "FPO";            break;
500     case IMAGE_DEBUG_TYPE_MISC:         str = "MISC";           break;
501     case IMAGE_DEBUG_TYPE_EXCEPTION:    str = "EXCEPTION";      break;
502     case IMAGE_DEBUG_TYPE_FIXUP:        str = "FIXUP";          break;
503     case IMAGE_DEBUG_TYPE_OMAP_TO_SRC:  str = "OMAP_TO_SRC";    break;
504     case IMAGE_DEBUG_TYPE_OMAP_FROM_SRC:str = "OMAP_FROM_SRC";  break;
505     case IMAGE_DEBUG_TYPE_BORLAND:      str = "BORLAND";        break;
506     case IMAGE_DEBUG_TYPE_RESERVED10:   str = "RESERVED10";     break;
507     }
508     printf("  Type:              %lu (%s)\n", idd->Type, str);
509     printf("  SizeOfData:        %lu\n", idd->SizeOfData);
510     printf("  AddressOfRawData:  %08lX\n", idd->AddressOfRawData);
511     printf("  PointerToRawData:  %08lX\n", idd->PointerToRawData);
512
513     switch (idd->Type)
514     {
515     case IMAGE_DEBUG_TYPE_UNKNOWN:
516         break;
517     case IMAGE_DEBUG_TYPE_COFF:
518         dump_coff(idd->PointerToRawData, idd->SizeOfData);
519         break;
520     case IMAGE_DEBUG_TYPE_CODEVIEW:
521         dump_codeview(idd->PointerToRawData, idd->SizeOfData);
522         break;
523     case IMAGE_DEBUG_TYPE_FPO:
524         dump_frame_pointer_omission(idd->PointerToRawData, idd->SizeOfData);
525         break;
526     case IMAGE_DEBUG_TYPE_MISC:
527     {
528         IMAGE_DEBUG_MISC* misc = PRD(idd->PointerToRawData, idd->SizeOfData);
529         if (!misc) {printf("Can't get misc debug information\n"); break;}
530         printf("    DataType:          %lu (%s)\n",
531                misc->DataType,
532                (misc->DataType == IMAGE_DEBUG_MISC_EXENAME) ? "Exe name" : "Unknown");
533         printf("    Length:            %lu\n", misc->Length);
534         printf("    Unicode:           %s\n", misc->Unicode ? "Yes" : "No");
535         printf("    Data:              %s\n", misc->Data);
536     }
537     break;
538     case IMAGE_DEBUG_TYPE_EXCEPTION:
539         break;
540     case IMAGE_DEBUG_TYPE_FIXUP:
541         break;
542     case IMAGE_DEBUG_TYPE_OMAP_TO_SRC:
543         break;
544     case IMAGE_DEBUG_TYPE_OMAP_FROM_SRC:
545         break;
546     case IMAGE_DEBUG_TYPE_BORLAND:
547         break;
548     case IMAGE_DEBUG_TYPE_RESERVED10:
549         break;
550     }
551     printf("\n");
552 }
553
554 static void     dump_dir_debug(void)
555 {
556     IMAGE_DEBUG_DIRECTORY*      debugDir = get_dir(IMAGE_FILE_DEBUG_DIRECTORY);
557     unsigned                    nb_dbg, i;
558
559     if (!debugDir) return;
560     nb_dbg = PE_nt_headers->OptionalHeader.DataDirectory[IMAGE_FILE_DEBUG_DIRECTORY].Size /
561         sizeof(*debugDir);
562     if (!nb_dbg) return;
563
564     printf("Debug Table (%u directories)\n", nb_dbg);
565
566     for (i = 0; i < nb_dbg; i++)
567     {
568         dump_dir_debug_dir(debugDir, i);
569         debugDir++;
570     }
571     printf("\n");
572 }
573
574 static void dump_dir_tls(void)
575 {
576     const IMAGE_TLS_DIRECTORY *dir = get_dir(IMAGE_FILE_THREAD_LOCAL_STORAGE);
577     const DWORD *callbacks;
578
579     if (!dir) return;
580     printf( "Thread Local Storage\n" );
581     printf( "  Raw data        %08lx-%08lx (data size %lx zero fill size %lx)\n",
582             dir->StartAddressOfRawData, dir->EndAddressOfRawData,
583             dir->EndAddressOfRawData - dir->StartAddressOfRawData,
584             dir->SizeOfZeroFill );
585     printf( "  Index address   %08lx\n", (DWORD)dir->AddressOfIndex );
586     printf( "  Characteristics %08lx\n", dir->Characteristics );
587     printf( "  Callbacks       %08lx -> {", (DWORD)dir->AddressOfCallBacks );
588     if (dir->AddressOfCallBacks)
589     {
590         DWORD   addr = (DWORD)dir->AddressOfCallBacks - PE_nt_headers->OptionalHeader.ImageBase;
591         while ((callbacks = RVA(addr, sizeof(DWORD))) && *callbacks)
592         {
593             printf( " %08lx", *callbacks );
594             addr += sizeof(DWORD);
595         }
596     }
597     printf(" }\n\n");
598 }
599
600 static void     dump_separate_dbg(void)
601 {
602     IMAGE_SEPARATE_DEBUG_HEADER*separateDebugHead = PRD(0, sizeof(separateDebugHead));
603     unsigned                    nb_dbg;
604     unsigned                    i;
605     IMAGE_DEBUG_DIRECTORY*      debugDir;
606
607     if (!separateDebugHead) {printf("Can't grab the separate header, aborting\n"); return;}
608
609     printf ("Signature:          %.2s (0x%4X)\n",
610             (char*)&separateDebugHead->Signature, separateDebugHead->Signature);
611     printf ("Flags:              0x%04X\n", separateDebugHead->Flags);
612     printf ("Machine:            0x%04X (%s)\n",
613             separateDebugHead->Machine, get_machine_str(separateDebugHead->Machine));
614     printf ("Characteristics:    0x%04X\n", separateDebugHead->Characteristics);
615     printf ("TimeDateStamp:      0x%08lX (%s)\n",
616             separateDebugHead->TimeDateStamp, get_time_str(separateDebugHead->TimeDateStamp));
617     printf ("CheckSum:           0x%08lX\n", separateDebugHead->CheckSum);
618     printf ("ImageBase:          0x%08lX\n", separateDebugHead->ImageBase);
619     printf ("SizeOfImage:        0x%08lX\n", separateDebugHead->SizeOfImage);
620     printf ("NumberOfSections:   0x%08lX\n", separateDebugHead->NumberOfSections);
621     printf ("ExportedNamesSize:  0x%08lX\n", separateDebugHead->ExportedNamesSize);
622     printf ("DebugDirectorySize: 0x%08lX\n", separateDebugHead->DebugDirectorySize);
623
624     if (!PRD(sizeof(IMAGE_SEPARATE_DEBUG_HEADER),
625              separateDebugHead->NumberOfSections * sizeof(IMAGE_SECTION_HEADER)))
626     {printf("Can't get the sections, aborting\n"); return;}
627
628     dump_sections(separateDebugHead + 1, separateDebugHead->NumberOfSections);
629
630     nb_dbg = separateDebugHead->DebugDirectorySize / sizeof(IMAGE_DEBUG_DIRECTORY);
631     debugDir = PRD(sizeof(IMAGE_SEPARATE_DEBUG_HEADER) +
632                    separateDebugHead->NumberOfSections * sizeof(IMAGE_SECTION_HEADER) +
633                    separateDebugHead->ExportedNamesSize,
634                    nb_dbg * sizeof(IMAGE_DEBUG_DIRECTORY));
635     if (!debugDir) {printf("Couldn't get the debug directory info, aborting\n");return;}
636
637     printf("Debug Table (%u directories)\n", nb_dbg);
638
639     for (i = 0; i < nb_dbg; i++)
640     {
641         dump_dir_debug_dir(debugDir, i);
642         debugDir++;
643     }
644 }
645
646 static void dump_unicode_str( const WCHAR *str, int len )
647 {
648     if (len == -1) for (len = 0; str[len]; len++) ;
649     printf( "L\"");
650     while (len-- > 0 && *str)
651     {
652         WCHAR c = *str++;
653         switch (c)
654         {
655         case '\n': printf( "\\n" ); break;
656         case '\r': printf( "\\r" ); break;
657         case '\t': printf( "\\t" ); break;
658         case '"':  printf( "\\\"" ); break;
659         case '\\': printf( "\\\\" ); break;
660         default:
661             if (c >= ' ' && c <= 126) putchar(c);
662             else printf( "\\u%04x",c);
663         }
664     }
665     printf( "\"" );
666 }
667
668 static const char *get_resource_type( unsigned int id )
669 {
670     static const char *types[] =
671     {
672         NULL,
673         "CURSOR",
674         "BITMAP",
675         "ICON",
676         "MENU",
677         "DIALOG",
678         "STRING",
679         "FONTDIR",
680         "FONT",
681         "ACCELERATOR",
682         "RCDATA",
683         "MESSAGETABLE",
684         "GROUP_CURSOR",
685         NULL,
686         "GROUP_ICON",
687         NULL,
688         "VERSION",
689         "DLGINCLUDE",
690         NULL,
691         "PLUGPLAY",
692         "VXD",
693         "ANICURSOR",
694         "ANIICON",
695         "HTML"
696     };
697
698     if ((size_t)id < sizeof(types)/sizeof(types[0])) return types[id];
699     return NULL;
700 }
701
702 void dump_data( const unsigned char *ptr, unsigned int size, const char *prefix )
703 {
704     unsigned int i, j;
705
706     printf( "%s", prefix );
707     if (!ptr)
708     {
709         printf("NULL\n");
710         return;
711     }
712     for (i = 0; i < size; i++)
713     {
714         printf( "%02x%c", ptr[i], (i % 16 == 7) ? '-' : ' ' );
715         if ((i % 16) == 15)
716         {
717             printf( " " );
718             for (j = 0; j < 16; j++)
719                 printf( "%c", isprint(ptr[i-15+j]) ? ptr[i-15+j] : '.' );
720             if (i < size-1) printf( "\n%s", prefix );
721         }
722     }
723     if (i % 16)
724     {
725         printf( "%*s ", 3 * (16-(i%16)), "" );
726         for (j = 0; j < i % 16; j++)
727             printf( "%c", isprint(ptr[i-(i%16)+j]) ? ptr[i-(i%16)+j] : '.' );
728     }
729     printf( "\n" );
730 }
731
732 /* dump an ASCII string with proper escaping */
733 static int dump_strA( const unsigned char *str, size_t len )
734 {
735     static const char escapes[32] = ".......abtnvfr.............e....";
736     char buffer[256];
737     char *pos = buffer;
738     int count = 0;
739
740     for (; len; str++, len--)
741     {
742         if (pos > buffer + sizeof(buffer) - 8)
743         {
744             fwrite( buffer, pos - buffer, 1, stdout );
745             count += pos - buffer;
746             pos = buffer;
747         }
748         if (*str > 127)  /* hex escape */
749         {
750             pos += sprintf( pos, "\\x%02x", *str );
751             continue;
752         }
753         if (*str < 32)  /* octal or C escape */
754         {
755             if (!*str && len == 1) continue;  /* do not output terminating NULL */
756             if (escapes[*str] != '.')
757                 pos += sprintf( pos, "\\%c", escapes[*str] );
758             else if (len > 1 && str[1] >= '0' && str[1] <= '7')
759                 pos += sprintf( pos, "\\%03o", *str );
760             else
761                 pos += sprintf( pos, "\\%o", *str );
762             continue;
763         }
764         if (*str == '\\') *pos++ = '\\';
765         *pos++ = *str;
766     }
767     fwrite( buffer, pos - buffer, 1, stdout );
768     count += pos - buffer;
769     return count;
770 }
771
772 /* dump a Unicode string with proper escaping */
773 static int dump_strW( const WCHAR *str, size_t len )
774 {
775     static const char escapes[32] = ".......abtnvfr.............e....";
776     char buffer[256];
777     char *pos = buffer;
778     int count = 0;
779
780     for (; len; str++, len--)
781     {
782         if (pos > buffer + sizeof(buffer) - 8)
783         {
784             fwrite( buffer, pos - buffer, 1, stdout );
785             count += pos - buffer;
786             pos = buffer;
787         }
788         if (*str > 127)  /* hex escape */
789         {
790             if (len > 1 && str[1] < 128 && isxdigit((char)str[1]))
791                 pos += sprintf( pos, "\\x%04x", *str );
792             else
793                 pos += sprintf( pos, "\\x%x", *str );
794             continue;
795         }
796         if (*str < 32)  /* octal or C escape */
797         {
798             if (!*str && len == 1) continue;  /* do not output terminating NULL */
799             if (escapes[*str] != '.')
800                 pos += sprintf( pos, "\\%c", escapes[*str] );
801             else if (len > 1 && str[1] >= '0' && str[1] <= '7')
802                 pos += sprintf( pos, "\\%03o", *str );
803             else
804                 pos += sprintf( pos, "\\%o", *str );
805             continue;
806         }
807         if (*str == '\\') *pos++ = '\\';
808         *pos++ = *str;
809     }
810     fwrite( buffer, pos - buffer, 1, stdout );
811     count += pos - buffer;
812     return count;
813 }
814
815 /* dump data for a STRING resource */
816 static void dump_string_data( const WCHAR *ptr, unsigned int size, unsigned int id, const char *prefix )
817 {
818     int i;
819
820     for (i = 0; i < 16 && size; i++)
821     {
822         unsigned len = *ptr++;
823
824         if (len >= size)
825         {
826             len = size;
827             size = 0;
828         }
829         else size -= len + 1;
830
831         if (len)
832         {
833             printf( "%s%04x \"", prefix, (id - 1) * 16 + i );
834             dump_strW( ptr, len );
835             printf( "\"\n" );
836             ptr += len;
837         }
838     }
839 }
840
841 /* dump data for a MESSAGETABLE resource */
842 static void dump_msgtable_data( const void *ptr, unsigned int size, unsigned int id, const char *prefix )
843 {
844     const MESSAGE_RESOURCE_DATA *data = ptr;
845     const MESSAGE_RESOURCE_BLOCK *block = data->Blocks;
846     unsigned i, j;
847
848     for (i = 0; i < data->NumberOfBlocks; i++, block++)
849     {
850         const MESSAGE_RESOURCE_ENTRY *entry;
851
852         entry = (const MESSAGE_RESOURCE_ENTRY *)((const char *)data + block->OffsetToEntries);
853         for (j = block->LowId; j <= block->HighId; j++)
854         {
855             if (entry->Flags & MESSAGE_RESOURCE_UNICODE)
856             {
857                 const WCHAR *str = (const WCHAR *)entry->Text;
858                 printf( "%s%08x L\"", prefix, j );
859                 dump_strW( str, strlenW(str) );
860                 printf( "\"\n" );
861             }
862             else
863             {
864                 printf( "%s%08x \"", prefix, j );
865                 dump_strA( entry->Text, strlen(entry->Text) );
866                 printf( "\"\n" );
867             }
868             entry = (const MESSAGE_RESOURCE_ENTRY *)((const char *)entry + entry->Length);
869         }
870     }
871 }
872
873 static void dump_dir_resource(void)
874 {
875     const IMAGE_RESOURCE_DIRECTORY *root = get_dir(IMAGE_FILE_RESOURCE_DIRECTORY);
876     const IMAGE_RESOURCE_DIRECTORY *namedir;
877     const IMAGE_RESOURCE_DIRECTORY *langdir;
878     const IMAGE_RESOURCE_DIRECTORY_ENTRY *e1, *e2, *e3;
879     const IMAGE_RESOURCE_DIR_STRING_U *string;
880     const IMAGE_RESOURCE_DATA_ENTRY *data;
881     int i, j, k;
882
883     if (!root) return;
884
885     printf( "Resources:" );
886
887     for (i = 0; i< root->NumberOfNamedEntries + root->NumberOfIdEntries; i++)
888     {
889         e1 = (const IMAGE_RESOURCE_DIRECTORY_ENTRY*)(root + 1) + i;
890         namedir = (const IMAGE_RESOURCE_DIRECTORY *)((const char *)root + e1->u2.s3.OffsetToDirectory);
891         for (j = 0; j < namedir->NumberOfNamedEntries + namedir->NumberOfIdEntries; j++)
892         {
893             e2 = (const IMAGE_RESOURCE_DIRECTORY_ENTRY*)(namedir + 1) + j;
894             langdir = (const IMAGE_RESOURCE_DIRECTORY *)((const char *)root + e2->u2.s3.OffsetToDirectory);
895             for (k = 0; k < langdir->NumberOfNamedEntries + langdir->NumberOfIdEntries; k++)
896             {
897                 e3 = (const IMAGE_RESOURCE_DIRECTORY_ENTRY*)(langdir + 1) + k;
898
899                 printf( "\n  " );
900                 if (e1->u1.s1.NameIsString)
901                 {
902                     string = (const IMAGE_RESOURCE_DIR_STRING_U*)((const char *)root + e1->u1.s1.NameOffset);
903                     dump_unicode_str( string->NameString, string->Length );
904                 }
905                 else
906                 {
907                     const char *type = get_resource_type( e1->u1.s2.Id );
908                     if (type) printf( "%s", type );
909                     else printf( "%04x", e1->u1.s2.Id );
910                 }
911
912                 printf( " Name=" );
913                 if (e2->u1.s1.NameIsString)
914                 {
915                     string = (const IMAGE_RESOURCE_DIR_STRING_U*) ((const char *)root + e2->u1.s1.NameOffset);
916                     dump_unicode_str( string->NameString, string->Length );
917                 }
918                 else
919                     printf( "%04x", e2->u1.s2.Id );
920
921                 printf( " Language=%04x:\n", e3->u1.s2.Id );
922                 data = (const IMAGE_RESOURCE_DATA_ENTRY *)((const char *)root + e3->u2.OffsetToData);
923                 if (e1->u1.s1.NameIsString)
924                 {
925                     dump_data( RVA( data->OffsetToData, data->Size ), data->Size, "        " );
926                 }
927                 else switch(e1->u1.s2.Id)
928                 {
929                 case 6:
930                     dump_string_data( RVA( data->OffsetToData, data->Size ), data->Size,
931                                       e2->u1.s2.Id, "    " );
932                     break;
933                 case 11:
934                     dump_msgtable_data( RVA( data->OffsetToData, data->Size ), data->Size,
935                                         e2->u1.s2.Id, "    " );
936                     break;
937                 default:
938                     dump_data( RVA( data->OffsetToData, data->Size ), data->Size, "        " );
939                     break;
940                 }
941             }
942         }
943     }
944     printf( "\n\n" );
945 }
946
947 static  void    do_dump( enum FileSig sig )
948 {
949     int all = (globals.dumpsect != NULL) && strcmp(globals.dumpsect, "ALL") == 0;
950
951     if (sig == SIG_NE)
952     {
953         ne_dump( PE_base, PE_total_len );
954         return;
955     }
956
957     if (sig == SIG_LE)
958     {
959         le_dump( PE_base, PE_total_len );
960         return;
961     }
962
963     if (globals.do_dumpheader)
964     {
965         dump_pe_header();
966         /* FIXME: should check ptr */
967         dump_sections((char*)PE_nt_headers + sizeof(DWORD) +
968                       sizeof(IMAGE_FILE_HEADER) + PE_nt_headers->FileHeader.SizeOfOptionalHeader,
969                       PE_nt_headers->FileHeader.NumberOfSections);
970     }
971     else if (!globals.dumpsect)
972     {
973         /* show at least something here */
974         dump_pe_header();
975     }
976
977     if (globals.dumpsect)
978     {
979         if (all || !strcmp(globals.dumpsect, "import"))
980             dump_dir_imported_functions();
981         if (all || !strcmp(globals.dumpsect, "export"))
982             dump_dir_exported_functions();
983         if (all || !strcmp(globals.dumpsect, "debug"))
984             dump_dir_debug();
985         if (all || !strcmp(globals.dumpsect, "resource"))
986             dump_dir_resource();
987         if (all || !strcmp(globals.dumpsect, "tls"))
988             dump_dir_tls();
989 #if 0
990         /* FIXME: not implemented yet */
991         if (all || !strcmp(globals.dumpsect, "reloc"))
992             dump_dir_reloc();
993 #endif
994     }
995 }
996
997 static  enum FileSig    check_headers(void)
998 {
999     WORD*               pw;
1000     DWORD*              pdw;
1001     IMAGE_DOS_HEADER*   dh;
1002     enum FileSig        sig;
1003
1004     pw = PRD(0, sizeof(WORD));
1005     if (!pw) {printf("Can't get main signature, aborting\n"); return 0;}
1006
1007     switch (*pw)
1008     {
1009     case IMAGE_DOS_SIGNATURE:
1010         sig = SIG_DOS;
1011         dh = PRD(0, sizeof(IMAGE_DOS_HEADER));
1012         if (dh && dh->e_lfanew >= sizeof(*dh)) /* reasonable DOS header ? */
1013         {
1014             /* the signature is the first DWORD */
1015             pdw = PRD(dh->e_lfanew, sizeof(DWORD));
1016             if (pdw)
1017             {
1018                 if (*pdw == IMAGE_NT_SIGNATURE)
1019                 {
1020                     PE_nt_headers = PRD(dh->e_lfanew, sizeof(DWORD)+sizeof(IMAGE_FILE_HEADER));
1021                     sig = SIG_PE;
1022                 }
1023                 else if (*(WORD *)pdw == IMAGE_OS2_SIGNATURE)
1024                 {
1025                     sig = SIG_NE;
1026                 }
1027                 else if (*(WORD *)pdw == IMAGE_VXD_SIGNATURE)
1028                 {
1029                     sig = SIG_LE;
1030                 }
1031                 else
1032                 {
1033                     printf("No PE Signature found\n");
1034                 }
1035             }
1036             else
1037             {
1038                 printf("Can't get the extented signature, aborting\n");
1039             }
1040         }
1041         break;
1042     case 0x4944: /* "DI" */
1043         sig = SIG_DBG;
1044         break;
1045     default:
1046         printf("No known main signature (%.2s/%x), aborting\n", (char*)pw, *pw);
1047         sig = SIG_UNKNOWN;
1048     }
1049
1050     return sig;
1051 }
1052
1053 static int pe_analysis(const char* name, void (*fn)(enum FileSig), enum FileSig wanted_sig)
1054 {
1055     int                 fd;
1056     enum FileSig        effective_sig;
1057     int                 ret = 1;
1058     struct stat         s;
1059
1060     setbuf(stdout, NULL);
1061
1062     fd = open(name, O_RDONLY | O_BINARY);
1063     if (fd == -1) fatal("Can't open file");
1064
1065     if (fstat(fd, &s) < 0) fatal("Can't get size");
1066     PE_total_len = s.st_size;
1067
1068 #ifdef HAVE_MMAP
1069     if ((PE_base = mmap(NULL, PE_total_len, PROT_READ, MAP_PRIVATE, fd, 0)) == (void *)-1)
1070 #endif
1071     {
1072         if (!(PE_base = malloc( PE_total_len ))) fatal( "Out of memory" );
1073         if ((unsigned long)read( fd, PE_base, PE_total_len ) != PE_total_len) fatal( "Cannot read file" );
1074     }
1075
1076     effective_sig = check_headers();
1077
1078     if (effective_sig == SIG_UNKNOWN)
1079     {
1080         printf("Can't get a recognized file signature, aborting\n");
1081         ret = 0;
1082     }
1083     else if (wanted_sig == SIG_UNKNOWN || wanted_sig == effective_sig)
1084     {
1085         switch (effective_sig)
1086         {
1087         case SIG_UNKNOWN: /* shouldn't happen... */
1088             ret = 0; break;
1089         case SIG_PE:
1090         case SIG_NE:
1091         case SIG_LE:
1092             printf("Contents of \"%s\": %ld bytes\n\n", name, PE_total_len);
1093             (*fn)(effective_sig);
1094             break;
1095         case SIG_DBG:
1096             dump_separate_dbg();
1097             break;
1098         case SIG_DOS:
1099             ret = 0; break;
1100         }
1101     }
1102     else
1103     {
1104         printf("Can't get a suitable file signature, aborting\n");
1105         ret = 0;
1106     }
1107
1108     if (ret) printf("Done dumping %s\n", name);
1109 #ifdef HAVE_MMAP
1110     if (munmap(PE_base, PE_total_len) == -1)
1111 #endif
1112     {
1113         free( PE_base );
1114     }
1115     close(fd);
1116
1117     return ret;
1118 }
1119
1120 void    dump_file(const char* name)
1121 {
1122     pe_analysis(name, do_dump, SIG_UNKNOWN);
1123 }
1124
1125 #if 0
1126 int     main(int argc, char* argv[])
1127 {
1128     if (argc != 2) fatal("usage");
1129     pe_analysis(argv[1], do_dump);
1130 }
1131 #endif
1132
1133 typedef struct _dll_symbol {
1134     size_t      ordinal;
1135     char       *symbol;
1136 } dll_symbol;
1137
1138 static dll_symbol *dll_symbols = NULL;
1139 static dll_symbol *dll_current_symbol = NULL;
1140
1141 /* Compare symbols by ordinal for qsort */
1142 static int symbol_cmp(const void *left, const void *right)
1143 {
1144     return ((const dll_symbol *)left)->ordinal > ((const dll_symbol *)right)->ordinal;
1145 }
1146
1147 /*******************************************************************
1148  *         dll_close
1149  *
1150  * Free resources used by DLL
1151  */
1152 /* FIXME: Not used yet
1153 static void dll_close (void)
1154 {
1155     dll_symbol* ds;
1156
1157     if (!dll_symbols) {
1158         fatal("No symbols");
1159     }
1160     for (ds = dll_symbols; ds->symbol; ds++)
1161         free(ds->symbol);
1162     free (dll_symbols);
1163     dll_symbols = NULL;
1164 }
1165 */
1166
1167 static  void    do_grab_sym( enum FileSig sig )
1168 {
1169     IMAGE_EXPORT_DIRECTORY      *exportDir = get_dir(IMAGE_FILE_EXPORT_DIRECTORY);
1170     unsigned                    i, j;
1171     DWORD*                      pName;
1172     DWORD*                      pFunc;
1173     WORD*                       pOrdl;
1174     char*                       ptr;
1175     DWORD*                      map;
1176
1177     if (!exportDir) return;
1178
1179     pName = RVA(exportDir->AddressOfNames, exportDir->NumberOfNames * sizeof(DWORD));
1180     if (!pName) {printf("Can't grab functions' name table\n"); return;}
1181     pOrdl = RVA(exportDir->AddressOfNameOrdinals, exportDir->NumberOfNames * sizeof(WORD));
1182     if (!pOrdl) {printf("Can't grab functions' ordinal table\n"); return;}
1183
1184     /* dll_close(); */
1185
1186     if (!(dll_symbols = (dll_symbol *) malloc((exportDir->NumberOfFunctions + 1) *
1187                                               sizeof (dll_symbol))))
1188         fatal ("Out of memory");
1189     if (exportDir->AddressOfFunctions != exportDir->NumberOfNames || exportDir->Base > 1)
1190         globals.do_ordinals = 1;
1191
1192     /* bit map of used funcs */
1193     map = calloc(((exportDir->NumberOfFunctions + 31) & ~31) / 32, sizeof(DWORD));
1194     if (!map) fatal("no memory");
1195
1196     for (j = 0; j < exportDir->NumberOfNames; j++, pOrdl++)
1197     {
1198         map[*pOrdl / 32] |= 1 << (*pOrdl % 32);
1199         ptr = RVA(*pName++, sizeof(DWORD));
1200         if (!ptr) ptr = "cant_get_function";
1201         dll_symbols[j].symbol = strdup(ptr);
1202         dll_symbols[j].ordinal = exportDir->Base + *pOrdl;
1203         assert(dll_symbols[j].symbol);
1204     }
1205     pFunc = RVA(exportDir->AddressOfFunctions, exportDir->NumberOfFunctions * sizeof(DWORD));
1206     if (!pFunc) {printf("Can't grab functions' address table\n"); return;}
1207
1208     for (i = 0; i < exportDir->NumberOfFunctions; i++)
1209     {
1210         if (pFunc[i] && !(map[i / 32] & (1 << (i % 32))))
1211         {
1212             char ordinal_text[256];
1213             /* Ordinal only entry */
1214             snprintf (ordinal_text, sizeof(ordinal_text), "%s_%lu",
1215                       globals.forward_dll ? globals.forward_dll : OUTPUT_UC_DLL_NAME,
1216                       exportDir->Base + i);
1217             str_toupper(ordinal_text);
1218             dll_symbols[j].symbol = strdup(ordinal_text);
1219             assert(dll_symbols[j].symbol);
1220             dll_symbols[j].ordinal = exportDir->Base + i;
1221             j++;
1222             assert(j <= exportDir->NumberOfFunctions);
1223         }
1224     }
1225     free(map);
1226
1227     if (NORMAL)
1228         printf("%lu named symbols in DLL, %lu total, %d unique (ordinal base = %ld)\n",
1229                exportDir->NumberOfNames, exportDir->NumberOfFunctions, j, exportDir->Base);
1230
1231     qsort( dll_symbols, j, sizeof(dll_symbol), symbol_cmp );
1232
1233     dll_symbols[j].symbol = NULL;
1234
1235     dll_current_symbol = dll_symbols;
1236 }
1237
1238 /*******************************************************************
1239  *         dll_open
1240  *
1241  * Open a DLL and read in exported symbols
1242  */
1243 int dll_open (const char *dll_name)
1244 {
1245     return pe_analysis(dll_name, do_grab_sym, SIG_PE);
1246 }
1247
1248 /*******************************************************************
1249  *         dll_next_symbol
1250  *
1251  * Get next exported symbol from dll
1252  */
1253 int dll_next_symbol (parsed_symbol * sym)
1254 {
1255     if (!dll_current_symbol->symbol)
1256         return 1;
1257
1258     assert (dll_symbols);
1259
1260     sym->symbol = strdup (dll_current_symbol->symbol);
1261     sym->ordinal = dll_current_symbol->ordinal;
1262     dll_current_symbol++;
1263     return 0;
1264 }