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