winedump: Add machine string for ARMv7.
[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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, 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
48 static const IMAGE_NT_HEADERS32*        PE_nt_headers;
49
50 const char *get_machine_str(int mach)
51 {
52     switch (mach)
53     {
54     case IMAGE_FILE_MACHINE_UNKNOWN:    return "Unknown";
55     case IMAGE_FILE_MACHINE_I860:       return "i860";
56     case IMAGE_FILE_MACHINE_I386:       return "i386";
57     case IMAGE_FILE_MACHINE_R3000:      return "R3000";
58     case IMAGE_FILE_MACHINE_R4000:      return "R4000";
59     case IMAGE_FILE_MACHINE_R10000:     return "R10000";
60     case IMAGE_FILE_MACHINE_ALPHA:      return "Alpha";
61     case IMAGE_FILE_MACHINE_POWERPC:    return "PowerPC";
62     case IMAGE_FILE_MACHINE_AMD64:      return "AMD64";
63     case IMAGE_FILE_MACHINE_IA64:       return "IA64";
64     case IMAGE_FILE_MACHINE_ARM:        return "ARM";
65     case IMAGE_FILE_MACHINE_ARMV7:      return "ARMv7";
66     case IMAGE_FILE_MACHINE_THUMB:      return "ARM Thumb";
67     case IMAGE_FILE_MACHINE_SPARC:      return "SPARC";
68     }
69     return "???";
70 }
71
72 static const void*      RVA(unsigned long rva, unsigned long len)
73 {
74     IMAGE_SECTION_HEADER*       sectHead;
75     int                         i;
76
77     if (rva == 0) return NULL;
78
79     sectHead = IMAGE_FIRST_SECTION(PE_nt_headers);
80     for (i = PE_nt_headers->FileHeader.NumberOfSections - 1; i >= 0; i--)
81     {
82         if (sectHead[i].VirtualAddress <= rva &&
83             rva + len <= (DWORD)sectHead[i].VirtualAddress + sectHead[i].SizeOfRawData)
84         {
85             /* return image import directory offset */
86             return PRD(sectHead[i].PointerToRawData + rva - sectHead[i].VirtualAddress, len);
87         }
88     }
89
90     return NULL;
91 }
92
93 static const IMAGE_NT_HEADERS32 *get_nt_header( void )
94 {
95     const IMAGE_DOS_HEADER *dos;
96     dos = PRD(0, sizeof(*dos));
97     if (!dos) return NULL;
98     return PRD(dos->e_lfanew, sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER));
99 }
100
101 static int is_fake_dll( void )
102 {
103     static const char fakedll_signature[] = "Wine placeholder DLL";
104     const IMAGE_DOS_HEADER *dos;
105
106     dos = PRD(0, sizeof(*dos) + sizeof(fakedll_signature));
107
108     if (dos && dos->e_lfanew >= sizeof(*dos) + sizeof(fakedll_signature) &&
109         !memcmp( dos + 1, fakedll_signature, sizeof(fakedll_signature) )) return TRUE;
110     return FALSE;
111 }
112
113 static const void *get_dir_and_size(unsigned int idx, unsigned int *size)
114 {
115     if(PE_nt_headers->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC)
116     {
117         const IMAGE_OPTIONAL_HEADER64 *opt = (const IMAGE_OPTIONAL_HEADER64*)&PE_nt_headers->OptionalHeader;
118         if (idx >= opt->NumberOfRvaAndSizes)
119             return NULL;
120         if(size)
121             *size = opt->DataDirectory[idx].Size;
122         return RVA(opt->DataDirectory[idx].VirtualAddress,
123                    opt->DataDirectory[idx].Size);
124     }
125     else
126     {
127         const IMAGE_OPTIONAL_HEADER32 *opt = (const IMAGE_OPTIONAL_HEADER32*)&PE_nt_headers->OptionalHeader;
128         if (idx >= opt->NumberOfRvaAndSizes)
129             return NULL;
130         if(size)
131             *size = opt->DataDirectory[idx].Size;
132         return RVA(opt->DataDirectory[idx].VirtualAddress,
133                    opt->DataDirectory[idx].Size);
134     }
135 }
136
137 static  const void*     get_dir(unsigned idx)
138 {
139     return get_dir_and_size(idx, 0);
140 }
141
142 static const char * const DirectoryNames[16] = {
143     "EXPORT",           "IMPORT",       "RESOURCE",     "EXCEPTION",
144     "SECURITY",         "BASERELOC",    "DEBUG",        "ARCHITECTURE",
145     "GLOBALPTR",        "TLS",          "LOAD_CONFIG",  "Bound IAT",
146     "IAT",              "Delay IAT",    "CLR Header", ""
147 };
148
149 static const char *get_magic_type(WORD magic)
150 {
151     switch(magic) {
152         case IMAGE_NT_OPTIONAL_HDR32_MAGIC:
153             return "32bit";
154         case IMAGE_NT_OPTIONAL_HDR64_MAGIC:
155             return "64bit";
156         case IMAGE_ROM_OPTIONAL_HDR_MAGIC:
157             return "ROM";
158     }
159     return "???";
160 }
161
162 static inline void print_word(const char *title, WORD value)
163 {
164     printf("  %-34s 0x%-4X         %u\n", title, value, value);
165 }
166
167 static inline void print_dword(const char *title, DWORD value)
168 {
169     printf("  %-34s 0x%-8x     %u\n", title, value, value);
170 }
171
172 static inline void print_longlong(const char *title, ULONGLONG value)
173 {
174     printf("  %-34s 0x", title);
175     if(value >> 32)
176         printf("%lx%08lx\n", (unsigned long)(value >> 32), (unsigned long)value);
177     else
178         printf("%lx\n", (unsigned long)value);
179 }
180
181 static inline void print_ver(const char *title, BYTE major, BYTE minor)
182 {
183     printf("  %-34s %u.%02u\n", title, major, minor);
184 }
185
186 static inline void print_subsys(const char *title, WORD value)
187 {
188     const char *str;
189     switch (value)
190     {
191         default:
192         case IMAGE_SUBSYSTEM_UNKNOWN:       str = "Unknown";        break;
193         case IMAGE_SUBSYSTEM_NATIVE:        str = "Native";         break;
194         case IMAGE_SUBSYSTEM_WINDOWS_GUI:   str = "Windows GUI";    break;
195         case IMAGE_SUBSYSTEM_WINDOWS_CUI:   str = "Windows CUI";    break;
196         case IMAGE_SUBSYSTEM_OS2_CUI:       str = "OS/2 CUI";       break;
197         case IMAGE_SUBSYSTEM_POSIX_CUI:     str = "Posix CUI";      break;
198         case IMAGE_SUBSYSTEM_NATIVE_WINDOWS:           str = "native Win9x driver";  break;
199         case IMAGE_SUBSYSTEM_WINDOWS_CE_GUI:           str = "Windows CE GUI";       break;
200         case IMAGE_SUBSYSTEM_EFI_APPLICATION:          str = "EFI application";      break;
201         case IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER:  str = "EFI driver (boot)";    break;
202         case IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER:       str = "EFI driver (runtime)"; break;
203         case IMAGE_SUBSYSTEM_EFI_ROM:                  str = "EFI ROM";              break;
204         case IMAGE_SUBSYSTEM_XBOX:                     str = "Xbox application";     break;
205         case IMAGE_SUBSYSTEM_WINDOWS_BOOT_APPLICATION: str = "Boot application";     break;
206     }
207     printf("  %-34s 0x%X (%s)\n", title, value, str);
208 }
209
210 static inline void print_dllflags(const char *title, WORD value)
211 {
212     printf("  %-34s 0x%X\n", title, value);
213 #define X(f,s) if (value & f) printf("    %s\n", s)
214     X(IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE,          "DYNAMIC_BASE");
215     X(IMAGE_DLLCHARACTERISTICS_FORCE_INTEGRITY,       "FORCE_INTEGRITY");
216     X(IMAGE_DLLCHARACTERISTICS_NX_COMPAT,             "NX_COMPAT");
217     X(IMAGE_DLLCHARACTERISTICS_NO_ISOLATION,          "NO_ISOLATION");
218     X(IMAGE_DLLCHARACTERISTICS_NO_SEH,                "NO_SEH");
219     X(IMAGE_DLLCHARACTERISTICS_NO_BIND,               "NO_BIND");
220     X(IMAGE_DLLCHARACTERISTICS_WDM_DRIVER,            "WDM_DRIVER");
221     X(IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE, "TERMINAL_SERVER_AWARE");
222 #undef X
223 }
224
225 static inline void print_datadirectory(DWORD n, const IMAGE_DATA_DIRECTORY *directory)
226 {
227     unsigned i;
228     printf("Data Directory\n");
229
230     for (i = 0; i < n && i < 16; i++)
231     {
232         printf("  %-12s rva: 0x%-8x  size: 0x%-8x\n",
233                DirectoryNames[i], directory[i].VirtualAddress,
234                directory[i].Size);
235     }
236 }
237
238 static void dump_optional_header32(const IMAGE_OPTIONAL_HEADER32 *image_oh, UINT header_size)
239 {
240     IMAGE_OPTIONAL_HEADER32 oh;
241     const IMAGE_OPTIONAL_HEADER32 *optionalHeader;
242
243     /* in case optional header is missing or partial */
244     memset(&oh, 0, sizeof(oh));
245     memcpy(&oh, image_oh, min(header_size, sizeof(oh)));
246     optionalHeader = &oh;
247
248     print_word("Magic", optionalHeader->Magic);
249     print_ver("linker version",
250               optionalHeader->MajorLinkerVersion, optionalHeader->MinorLinkerVersion);
251     print_dword("size of code", optionalHeader->SizeOfCode);
252     print_dword("size of initialized data", optionalHeader->SizeOfInitializedData);
253     print_dword("size of uninitialized data", optionalHeader->SizeOfUninitializedData);
254     print_dword("entrypoint RVA", optionalHeader->AddressOfEntryPoint);
255     print_dword("base of code", optionalHeader->BaseOfCode);
256     print_dword("base of data", optionalHeader->BaseOfData);
257     print_dword("image base", optionalHeader->ImageBase);
258     print_dword("section align", optionalHeader->SectionAlignment);
259     print_dword("file align", optionalHeader->FileAlignment);
260     print_ver("required OS version",
261               optionalHeader->MajorOperatingSystemVersion, optionalHeader->MinorOperatingSystemVersion);
262     print_ver("image version",
263               optionalHeader->MajorImageVersion, optionalHeader->MinorImageVersion);
264     print_ver("subsystem version",
265               optionalHeader->MajorSubsystemVersion, optionalHeader->MinorSubsystemVersion);
266     print_dword("Win32 Version", optionalHeader->Win32VersionValue);
267     print_dword("size of image", optionalHeader->SizeOfImage);
268     print_dword("size of headers", optionalHeader->SizeOfHeaders);
269     print_dword("checksum", optionalHeader->CheckSum);
270     print_subsys("Subsystem", optionalHeader->Subsystem);
271     print_dllflags("DLL characteristics:", optionalHeader->DllCharacteristics);
272     print_dword("stack reserve size", optionalHeader->SizeOfStackReserve);
273     print_dword("stack commit size", optionalHeader->SizeOfStackCommit);
274     print_dword("heap reserve size", optionalHeader->SizeOfHeapReserve);
275     print_dword("heap commit size", optionalHeader->SizeOfHeapCommit);
276     print_dword("loader flags", optionalHeader->LoaderFlags);
277     print_dword("RVAs & sizes", optionalHeader->NumberOfRvaAndSizes);
278     printf("\n");
279     print_datadirectory(optionalHeader->NumberOfRvaAndSizes, optionalHeader->DataDirectory);
280     printf("\n");
281 }
282
283 static void dump_optional_header64(const IMAGE_OPTIONAL_HEADER64 *image_oh, UINT header_size)
284 {
285     IMAGE_OPTIONAL_HEADER64 oh;
286     const IMAGE_OPTIONAL_HEADER64 *optionalHeader;
287
288     /* in case optional header is missing or partial */
289     memset(&oh, 0, sizeof(oh));
290     memcpy(&oh, image_oh, min(header_size, sizeof(oh)));
291     optionalHeader = &oh;
292
293     print_word("Magic", optionalHeader->Magic);
294     print_ver("linker version",
295               optionalHeader->MajorLinkerVersion, optionalHeader->MinorLinkerVersion);
296     print_dword("size of code", optionalHeader->SizeOfCode);
297     print_dword("size of initialized data", optionalHeader->SizeOfInitializedData);
298     print_dword("size of uninitialized data", optionalHeader->SizeOfUninitializedData);
299     print_dword("entrypoint RVA", optionalHeader->AddressOfEntryPoint);
300     print_dword("base of code", optionalHeader->BaseOfCode);
301     print_longlong("image base", optionalHeader->ImageBase);
302     print_dword("section align", optionalHeader->SectionAlignment);
303     print_dword("file align", optionalHeader->FileAlignment);
304     print_ver("required OS version",
305               optionalHeader->MajorOperatingSystemVersion, optionalHeader->MinorOperatingSystemVersion);
306     print_ver("image version",
307               optionalHeader->MajorImageVersion, optionalHeader->MinorImageVersion);
308     print_ver("subsystem version",
309               optionalHeader->MajorSubsystemVersion, optionalHeader->MinorSubsystemVersion);
310     print_dword("Win32 Version", optionalHeader->Win32VersionValue);
311     print_dword("size of image", optionalHeader->SizeOfImage);
312     print_dword("size of headers", optionalHeader->SizeOfHeaders);
313     print_dword("checksum", optionalHeader->CheckSum);
314     print_subsys("Subsystem", optionalHeader->Subsystem);
315     print_dllflags("DLL characteristics:", optionalHeader->DllCharacteristics);
316     print_longlong("stack reserve size", optionalHeader->SizeOfStackReserve);
317     print_longlong("stack commit size", optionalHeader->SizeOfStackCommit);
318     print_longlong("heap reserve size", optionalHeader->SizeOfHeapReserve);
319     print_longlong("heap commit size", optionalHeader->SizeOfHeapCommit);
320     print_dword("loader flags", optionalHeader->LoaderFlags);
321     print_dword("RVAs & sizes", optionalHeader->NumberOfRvaAndSizes);
322     printf("\n");
323     print_datadirectory(optionalHeader->NumberOfRvaAndSizes, optionalHeader->DataDirectory);
324     printf("\n");
325 }
326
327 void dump_optional_header(const IMAGE_OPTIONAL_HEADER32 *optionalHeader, UINT header_size)
328 {
329     printf("Optional Header (%s)\n", get_magic_type(optionalHeader->Magic));
330
331     switch(optionalHeader->Magic) {
332         case IMAGE_NT_OPTIONAL_HDR32_MAGIC:
333             dump_optional_header32(optionalHeader, header_size);
334             break;
335         case IMAGE_NT_OPTIONAL_HDR64_MAGIC:
336             dump_optional_header64((const IMAGE_OPTIONAL_HEADER64 *)optionalHeader, header_size);
337             break;
338         default:
339             printf("  Unknown optional header magic: 0x%-4X\n", optionalHeader->Magic);
340             break;
341     }
342 }
343
344 void dump_file_header(const IMAGE_FILE_HEADER *fileHeader)
345 {
346     printf("File Header\n");
347
348     printf("  Machine:                      %04X (%s)\n",
349            fileHeader->Machine, get_machine_str(fileHeader->Machine));
350     printf("  Number of Sections:           %d\n", fileHeader->NumberOfSections);
351     printf("  TimeDateStamp:                %08X (%s) offset %lu\n",
352            fileHeader->TimeDateStamp, get_time_str(fileHeader->TimeDateStamp),
353            Offset(&(fileHeader->TimeDateStamp)));
354     printf("  PointerToSymbolTable:         %08X\n", fileHeader->PointerToSymbolTable);
355     printf("  NumberOfSymbols:              %08X\n", fileHeader->NumberOfSymbols);
356     printf("  SizeOfOptionalHeader:         %04X\n", fileHeader->SizeOfOptionalHeader);
357     printf("  Characteristics:              %04X\n", fileHeader->Characteristics);
358 #define X(f,s)  if (fileHeader->Characteristics & f) printf("    %s\n", s)
359     X(IMAGE_FILE_RELOCS_STRIPPED,       "RELOCS_STRIPPED");
360     X(IMAGE_FILE_EXECUTABLE_IMAGE,      "EXECUTABLE_IMAGE");
361     X(IMAGE_FILE_LINE_NUMS_STRIPPED,    "LINE_NUMS_STRIPPED");
362     X(IMAGE_FILE_LOCAL_SYMS_STRIPPED,   "LOCAL_SYMS_STRIPPED");
363     X(IMAGE_FILE_AGGRESIVE_WS_TRIM,     "AGGRESIVE_WS_TRIM");
364     X(IMAGE_FILE_LARGE_ADDRESS_AWARE,   "LARGE_ADDRESS_AWARE");
365     X(IMAGE_FILE_16BIT_MACHINE,         "16BIT_MACHINE");
366     X(IMAGE_FILE_BYTES_REVERSED_LO,     "BYTES_REVERSED_LO");
367     X(IMAGE_FILE_32BIT_MACHINE,         "32BIT_MACHINE");
368     X(IMAGE_FILE_DEBUG_STRIPPED,        "DEBUG_STRIPPED");
369     X(IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP,       "REMOVABLE_RUN_FROM_SWAP");
370     X(IMAGE_FILE_NET_RUN_FROM_SWAP,     "NET_RUN_FROM_SWAP");
371     X(IMAGE_FILE_SYSTEM,                "SYSTEM");
372     X(IMAGE_FILE_DLL,                   "DLL");
373     X(IMAGE_FILE_UP_SYSTEM_ONLY,        "UP_SYSTEM_ONLY");
374     X(IMAGE_FILE_BYTES_REVERSED_HI,     "BYTES_REVERSED_HI");
375 #undef X
376     printf("\n");
377 }
378
379 static  void    dump_pe_header(void)
380 {
381     dump_file_header(&PE_nt_headers->FileHeader);
382     dump_optional_header((const IMAGE_OPTIONAL_HEADER32*)&PE_nt_headers->OptionalHeader, PE_nt_headers->FileHeader.SizeOfOptionalHeader);
383 }
384
385 void dump_section(const IMAGE_SECTION_HEADER *sectHead, const char* strtable)
386 {
387         unsigned offset;
388
389         /* long section name ? */
390         if (strtable && sectHead->Name[0] == '/' &&
391             ((offset = atoi((const char*)sectHead->Name + 1)) < *(const DWORD*)strtable))
392             printf("  %.8s (%s)", sectHead->Name, strtable + offset);
393         else
394             printf("  %-8.8s", sectHead->Name);
395         printf("   VirtSize: 0x%08x  VirtAddr:  0x%08x\n",
396                sectHead->Misc.VirtualSize, sectHead->VirtualAddress);
397         printf("    raw data offs:   0x%08x  raw data size: 0x%08x\n",
398                sectHead->PointerToRawData, sectHead->SizeOfRawData);
399         printf("    relocation offs: 0x%08x  relocations:   0x%08x\n",
400                sectHead->PointerToRelocations, sectHead->NumberOfRelocations);
401         printf("    line # offs:     %-8u  line #'s:      %-8u\n",
402                sectHead->PointerToLinenumbers, sectHead->NumberOfLinenumbers);
403         printf("    characteristics: 0x%08x\n", sectHead->Characteristics);
404         printf("    ");
405 #define X(b,s)  if (sectHead->Characteristics & b) printf("  " s)
406 /* #define IMAGE_SCN_TYPE_REG                   0x00000000 - Reserved */
407 /* #define IMAGE_SCN_TYPE_DSECT                 0x00000001 - Reserved */
408 /* #define IMAGE_SCN_TYPE_NOLOAD                0x00000002 - Reserved */
409 /* #define IMAGE_SCN_TYPE_GROUP                 0x00000004 - Reserved */
410 /* #define IMAGE_SCN_TYPE_NO_PAD                0x00000008 - Reserved */
411 /* #define IMAGE_SCN_TYPE_COPY                  0x00000010 - Reserved */
412
413         X(IMAGE_SCN_CNT_CODE,                   "CODE");
414         X(IMAGE_SCN_CNT_INITIALIZED_DATA,       "INITIALIZED_DATA");
415         X(IMAGE_SCN_CNT_UNINITIALIZED_DATA,     "UNINITIALIZED_DATA");
416
417         X(IMAGE_SCN_LNK_OTHER,                  "LNK_OTHER");
418         X(IMAGE_SCN_LNK_INFO,                   "LNK_INFO");
419 /* #define      IMAGE_SCN_TYPE_OVER             0x00000400 - Reserved */
420         X(IMAGE_SCN_LNK_REMOVE,                 "LNK_REMOVE");
421         X(IMAGE_SCN_LNK_COMDAT,                 "LNK_COMDAT");
422
423 /*                                              0x00002000 - Reserved */
424 /* #define IMAGE_SCN_MEM_PROTECTED              0x00004000 - Obsolete */
425         X(IMAGE_SCN_MEM_FARDATA,                "MEM_FARDATA");
426
427 /* #define IMAGE_SCN_MEM_SYSHEAP                0x00010000 - Obsolete */
428         X(IMAGE_SCN_MEM_PURGEABLE,              "MEM_PURGEABLE");
429         X(IMAGE_SCN_MEM_16BIT,                  "MEM_16BIT");
430         X(IMAGE_SCN_MEM_LOCKED,                 "MEM_LOCKED");
431         X(IMAGE_SCN_MEM_PRELOAD,                "MEM_PRELOAD");
432
433         switch (sectHead->Characteristics & IMAGE_SCN_ALIGN_MASK)
434         {
435 #define X2(b,s) case b: printf("  " s); break
436         X2(IMAGE_SCN_ALIGN_1BYTES,              "ALIGN_1BYTES");
437         X2(IMAGE_SCN_ALIGN_2BYTES,              "ALIGN_2BYTES");
438         X2(IMAGE_SCN_ALIGN_4BYTES,              "ALIGN_4BYTES");
439         X2(IMAGE_SCN_ALIGN_8BYTES,              "ALIGN_8BYTES");
440         X2(IMAGE_SCN_ALIGN_16BYTES,             "ALIGN_16BYTES");
441         X2(IMAGE_SCN_ALIGN_32BYTES,             "ALIGN_32BYTES");
442         X2(IMAGE_SCN_ALIGN_64BYTES,             "ALIGN_64BYTES");
443         X2(IMAGE_SCN_ALIGN_128BYTES,            "ALIGN_128BYTES");
444         X2(IMAGE_SCN_ALIGN_256BYTES,            "ALIGN_256BYTES");
445         X2(IMAGE_SCN_ALIGN_512BYTES,            "ALIGN_512BYTES");
446         X2(IMAGE_SCN_ALIGN_1024BYTES,           "ALIGN_1024BYTES");
447         X2(IMAGE_SCN_ALIGN_2048BYTES,           "ALIGN_2048BYTES");
448         X2(IMAGE_SCN_ALIGN_4096BYTES,           "ALIGN_4096BYTES");
449         X2(IMAGE_SCN_ALIGN_8192BYTES,           "ALIGN_8192BYTES");
450 #undef X2
451         }
452
453         X(IMAGE_SCN_LNK_NRELOC_OVFL,            "LNK_NRELOC_OVFL");
454
455         X(IMAGE_SCN_MEM_DISCARDABLE,            "MEM_DISCARDABLE");
456         X(IMAGE_SCN_MEM_NOT_CACHED,             "MEM_NOT_CACHED");
457         X(IMAGE_SCN_MEM_NOT_PAGED,              "MEM_NOT_PAGED");
458         X(IMAGE_SCN_MEM_SHARED,                 "MEM_SHARED");
459         X(IMAGE_SCN_MEM_EXECUTE,                "MEM_EXECUTE");
460         X(IMAGE_SCN_MEM_READ,                   "MEM_READ");
461         X(IMAGE_SCN_MEM_WRITE,                  "MEM_WRITE");
462 #undef X
463         printf("\n\n");
464 }
465
466 static void dump_sections(const void *base, const void* addr, unsigned num_sect)
467 {
468     const IMAGE_SECTION_HEADER* sectHead = addr;
469     unsigned                    i;
470     const char*                 strtable;
471
472     if (PE_nt_headers->FileHeader.PointerToSymbolTable && PE_nt_headers->FileHeader.NumberOfSymbols)
473     {
474         strtable = (const char*)base +
475             PE_nt_headers->FileHeader.PointerToSymbolTable +
476             PE_nt_headers->FileHeader.NumberOfSymbols * sizeof(IMAGE_SYMBOL);
477     }
478     else strtable = NULL;
479
480     printf("Section Table\n");
481     for (i = 0; i < num_sect; i++, sectHead++)
482     {
483         dump_section(sectHead, strtable);
484
485         if (globals.do_dump_rawdata)
486         {
487             dump_data((const unsigned char *)base + sectHead->PointerToRawData, sectHead->SizeOfRawData, "    " );
488             printf("\n");
489         }
490     }
491 }
492
493 static  void    dump_dir_exported_functions(void)
494 {
495     unsigned int size = 0;
496     const IMAGE_EXPORT_DIRECTORY*exportDir = get_dir_and_size(IMAGE_FILE_EXPORT_DIRECTORY, &size);
497     unsigned int                i;
498     const DWORD*                pFunc;
499     const DWORD*                pName;
500     const WORD*                 pOrdl;
501     DWORD*                      funcs;
502
503     if (!exportDir) return;
504
505     printf("Exports table:\n");
506     printf("\n");
507     printf("  Name:            %s\n", (const char*)RVA(exportDir->Name, sizeof(DWORD)));
508     printf("  Characteristics: %08x\n", exportDir->Characteristics);
509     printf("  TimeDateStamp:   %08X %s\n",
510            exportDir->TimeDateStamp, get_time_str(exportDir->TimeDateStamp));
511     printf("  Version:         %u.%02u\n", exportDir->MajorVersion, exportDir->MinorVersion);
512     printf("  Ordinal base:    %u\n", exportDir->Base);
513     printf("  # of functions:  %u\n", exportDir->NumberOfFunctions);
514     printf("  # of Names:      %u\n", exportDir->NumberOfNames);
515     printf("Addresses of functions: %08X\n", exportDir->AddressOfFunctions);
516     printf("Addresses of name ordinals: %08X\n", exportDir->AddressOfNameOrdinals);
517     printf("Addresses of names: %08X\n", exportDir->AddressOfNames);
518     printf("\n");
519     printf("  Entry Pt  Ordn  Name\n");
520
521     pFunc = RVA(exportDir->AddressOfFunctions, exportDir->NumberOfFunctions * sizeof(DWORD));
522     if (!pFunc) {printf("Can't grab functions' address table\n"); return;}
523     pName = RVA(exportDir->AddressOfNames, exportDir->NumberOfNames * sizeof(DWORD));
524     pOrdl = RVA(exportDir->AddressOfNameOrdinals, exportDir->NumberOfNames * sizeof(WORD));
525
526     funcs = calloc( exportDir->NumberOfFunctions, sizeof(*funcs) );
527     if (!funcs) fatal("no memory");
528
529     for (i = 0; i < exportDir->NumberOfNames; i++) funcs[pOrdl[i]] = pName[i];
530
531     for (i = 0; i < exportDir->NumberOfFunctions; i++)
532     {
533         if (!pFunc[i]) continue;
534         printf("  %08X %5u ", pFunc[i], exportDir->Base + i);
535         if (funcs[i])
536             printf("%s", get_symbol_str((const char*)RVA(funcs[i], sizeof(DWORD))));
537         else
538             printf("<by ordinal>");
539
540         /* check for forwarded function */
541         if ((const char *)RVA(pFunc[i],1) >= (const char *)exportDir &&
542             (const char *)RVA(pFunc[i],1) < (const char *)exportDir + size)
543             printf(" (-> %s)", (const char *)RVA(pFunc[i],1));
544         printf("\n");
545     }
546     free(funcs);
547     printf("\n");
548 }
549
550
551 struct runtime_function
552 {
553     DWORD BeginAddress;
554     DWORD EndAddress;
555     DWORD UnwindData;
556 };
557
558 union handler_data
559 {
560     struct runtime_function chain;
561     DWORD handler;
562 };
563
564 struct opcode
565 {
566     BYTE offset;
567     BYTE code : 4;
568     BYTE info : 4;
569 };
570
571 struct unwind_info
572 {
573     BYTE version : 3;
574     BYTE flags : 5;
575     BYTE prolog;
576     BYTE count;
577     BYTE frame_reg : 4;
578     BYTE frame_offset : 4;
579     struct opcode opcodes[1];  /* count entries */
580     /* followed by union handler_data */
581 };
582
583 #define UWOP_PUSH_NONVOL     0
584 #define UWOP_ALLOC_LARGE     1
585 #define UWOP_ALLOC_SMALL     2
586 #define UWOP_SET_FPREG       3
587 #define UWOP_SAVE_NONVOL     4
588 #define UWOP_SAVE_NONVOL_FAR 5
589 #define UWOP_SAVE_XMM128     8
590 #define UWOP_SAVE_XMM128_FAR 9
591 #define UWOP_PUSH_MACHFRAME  10
592
593 #define UNW_FLAG_EHANDLER  1
594 #define UNW_FLAG_UHANDLER  2
595 #define UNW_FLAG_CHAININFO 4
596
597 static void dump_x86_64_unwind_info( const struct runtime_function *function )
598 {
599     static const char * const reg_names[16] =
600         { "rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi",
601           "r8",  "r9",  "r10", "r11", "r12", "r13", "r14", "r15" };
602
603     const union handler_data *handler_data;
604     const struct unwind_info *info;
605     unsigned int i, count;
606
607     printf( "\nFunction %08x-%08x:\n", function->BeginAddress, function->EndAddress );
608     if (function->UnwindData & 1)
609     {
610         const struct runtime_function *next = RVA( function->UnwindData & ~1, sizeof(*next) );
611         printf( "  -> function %08x-%08x\n", next->BeginAddress, next->EndAddress );
612         return;
613     }
614     info = RVA( function->UnwindData, sizeof(*info) );
615
616     printf( "  unwind info at %08x\n", function->UnwindData );
617     if (info->version != 1)
618     {
619         printf( "    *** unknown version %u\n", info->version );
620         return;
621     }
622     printf( "    flags %x", info->flags );
623     if (info->flags & UNW_FLAG_EHANDLER) printf( " EHANDLER" );
624     if (info->flags & UNW_FLAG_UHANDLER) printf( " UHANDLER" );
625     if (info->flags & UNW_FLAG_CHAININFO) printf( " CHAININFO" );
626     printf( "\n    prolog 0x%x bytes\n", info->prolog );
627
628     if (info->frame_reg)
629         printf( "    frame register %s offset 0x%x(%%rsp)\n",
630                 reg_names[info->frame_reg], info->frame_offset * 16 );
631
632     for (i = 0; i < info->count; i++)
633     {
634         printf( "      0x%02x: ", info->opcodes[i].offset );
635         switch (info->opcodes[i].code)
636         {
637         case UWOP_PUSH_NONVOL:
638             printf( "push %%%s\n", reg_names[info->opcodes[i].info] );
639             break;
640         case UWOP_ALLOC_LARGE:
641             if (info->opcodes[i].info)
642             {
643                 count = *(const DWORD *)&info->opcodes[i+1];
644                 i += 2;
645             }
646             else
647             {
648                 count = *(const USHORT *)&info->opcodes[i+1] * 8;
649                 i++;
650             }
651             printf( "sub $0x%x,%%rsp\n", count );
652             break;
653         case UWOP_ALLOC_SMALL:
654             count = (info->opcodes[i].info + 1) * 8;
655             printf( "sub $0x%x,%%rsp\n", count );
656             break;
657         case UWOP_SET_FPREG:
658             printf( "lea 0x%x(%%rsp),%s\n",
659                     info->frame_offset * 16, reg_names[info->frame_reg] );
660             break;
661         case UWOP_SAVE_NONVOL:
662             count = *(const USHORT *)&info->opcodes[i+1] * 8;
663             printf( "mov %%%s,0x%x(%%rsp)\n", reg_names[info->opcodes[i].info], count );
664             i++;
665             break;
666         case UWOP_SAVE_NONVOL_FAR:
667             count = *(const DWORD *)&info->opcodes[i+1];
668             printf( "mov %%%s,0x%x(%%rsp)\n", reg_names[info->opcodes[i].info], count );
669             i += 2;
670             break;
671         case UWOP_SAVE_XMM128:
672             count = *(const USHORT *)&info->opcodes[i+1] * 16;
673             printf( "movaps %%xmm%u,0x%x(%%rsp)\n", info->opcodes[i].info, count );
674             i++;
675             break;
676         case UWOP_SAVE_XMM128_FAR:
677             count = *(const DWORD *)&info->opcodes[i+1];
678             printf( "movaps %%xmm%u,0x%x(%%rsp)\n", info->opcodes[i].info, count );
679             i += 2;
680             break;
681         case UWOP_PUSH_MACHFRAME:
682             printf( "PUSH_MACHFRAME %u\n", info->opcodes[i].info );
683             break;
684         default:
685             printf( "*** unknown code %u\n", info->opcodes[i].code );
686             break;
687         }
688     }
689
690     handler_data = (const union handler_data *)&info->opcodes[(info->count + 1) & ~1];
691     if (info->flags & UNW_FLAG_CHAININFO)
692     {
693         printf( "    -> function %08x-%08x\n",
694                 handler_data->chain.BeginAddress, handler_data->chain.EndAddress );
695         return;
696     }
697     if (info->flags & (UNW_FLAG_EHANDLER | UNW_FLAG_UHANDLER))
698         printf( "    handler %08x data at %08x\n", handler_data->handler,
699                 (ULONG)(function->UnwindData + (const char *)(&handler_data->handler + 1) - (const char *)info ));
700 }
701
702 static void dump_dir_exceptions(void)
703 {
704     unsigned int i, size = 0;
705     const struct runtime_function *funcs = get_dir_and_size(IMAGE_FILE_EXCEPTION_DIRECTORY, &size);
706     const IMAGE_FILE_HEADER *file_header = &PE_nt_headers->FileHeader;
707
708     if (!funcs) return;
709
710     if (file_header->Machine == IMAGE_FILE_MACHINE_AMD64)
711     {
712         size /= sizeof(*funcs);
713         printf( "Exception info (%u functions):\n", size );
714         for (i = 0; i < size; i++) dump_x86_64_unwind_info( funcs + i );
715     }
716     else printf( "Exception information not supported for %s binaries\n",
717                  get_machine_str(file_header->Machine));
718 }
719
720
721 static void dump_image_thunk_data64(const IMAGE_THUNK_DATA64 *il)
722 {
723     /* FIXME: This does not properly handle large images */
724     const IMAGE_IMPORT_BY_NAME* iibn;
725     for (; il->u1.Ordinal; il++)
726     {
727         if (IMAGE_SNAP_BY_ORDINAL64(il->u1.Ordinal))
728             printf("  %4u  <by ordinal>\n", (DWORD)IMAGE_ORDINAL64(il->u1.Ordinal));
729         else
730         {
731             iibn = RVA((DWORD)il->u1.AddressOfData, sizeof(DWORD));
732             if (!iibn)
733                 printf("Can't grab import by name info, skipping to next ordinal\n");
734             else
735                 printf("  %4u  %s %x\n", iibn->Hint, iibn->Name, (DWORD)il->u1.AddressOfData);
736         }
737     }
738 }
739
740 static void dump_image_thunk_data32(const IMAGE_THUNK_DATA32 *il, int offset)
741 {
742     const IMAGE_IMPORT_BY_NAME* iibn;
743     for (; il->u1.Ordinal; il++)
744     {
745         if (IMAGE_SNAP_BY_ORDINAL32(il->u1.Ordinal))
746             printf("  %4u  <by ordinal>\n", IMAGE_ORDINAL32(il->u1.Ordinal));
747         else
748         {
749             iibn = RVA((DWORD)il->u1.AddressOfData - offset, sizeof(DWORD));
750             if (!iibn)
751                 printf("Can't grab import by name info, skipping to next ordinal\n");
752             else
753                 printf("  %4u  %s %x\n", iibn->Hint, iibn->Name, (DWORD)il->u1.AddressOfData);
754         }
755     }
756 }
757
758 static  void    dump_dir_imported_functions(void)
759 {
760     unsigned directorySize;
761     const IMAGE_IMPORT_DESCRIPTOR* importDesc = get_dir_and_size(IMAGE_FILE_IMPORT_DIRECTORY, &directorySize);
762
763     if (!importDesc)    return;
764
765     printf("Import Table size: %08x\n", directorySize);/* FIXME */
766
767     for (;;)
768     {
769         const IMAGE_THUNK_DATA32*       il;
770
771         if (!importDesc->Name || !importDesc->FirstThunk) break;
772
773         printf("  offset %08lx %s\n", Offset(importDesc), (const char*)RVA(importDesc->Name, sizeof(DWORD)));
774         printf("  Hint/Name Table: %08X\n", (DWORD)importDesc->u.OriginalFirstThunk);
775         printf("  TimeDateStamp:   %08X (%s)\n",
776                importDesc->TimeDateStamp, get_time_str(importDesc->TimeDateStamp));
777         printf("  ForwarderChain:  %08X\n", importDesc->ForwarderChain);
778         printf("  First thunk RVA: %08X\n", (DWORD)importDesc->FirstThunk);
779
780         printf("  Ordn  Name\n");
781
782         il = (importDesc->u.OriginalFirstThunk != 0) ?
783             RVA((DWORD)importDesc->u.OriginalFirstThunk, sizeof(DWORD)) :
784             RVA((DWORD)importDesc->FirstThunk, sizeof(DWORD));
785
786         if (!il)
787             printf("Can't grab thunk data, going to next imported DLL\n");
788         else
789         {
790             if(PE_nt_headers->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC)
791                 dump_image_thunk_data64((const IMAGE_THUNK_DATA64*)il);
792             else
793                 dump_image_thunk_data32(il, 0);
794             printf("\n");
795         }
796         importDesc++;
797     }
798     printf("\n");
799 }
800
801 static void dump_dir_delay_imported_functions(void)
802 {
803     unsigned  directorySize;
804     const struct ImgDelayDescr
805     {
806         DWORD grAttrs;
807         DWORD szName;
808         DWORD phmod;
809         DWORD pIAT;
810         DWORD pINT;
811         DWORD pBoundIAT;
812         DWORD pUnloadIAT;
813         DWORD dwTimeStamp;
814     } *importDesc = get_dir_and_size(IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT, &directorySize);
815
816     if (!importDesc) return;
817
818     printf("Delay Import Table size: %08x\n", directorySize); /* FIXME */
819
820     for (;;)
821     {
822         const IMAGE_THUNK_DATA32*       il;
823         int                             offset = (importDesc->grAttrs & 1) ? 0 : PE_nt_headers->OptionalHeader.ImageBase;
824
825         if (!importDesc->szName || !importDesc->pIAT || !importDesc->pINT) break;
826
827         printf("  grAttrs %08x offset %08lx %s\n", importDesc->grAttrs, Offset(importDesc),
828                (const char *)RVA(importDesc->szName - offset, sizeof(DWORD)));
829         printf("  Hint/Name Table: %08x\n", importDesc->pINT);
830         printf("  TimeDateStamp:   %08X (%s)\n",
831                importDesc->dwTimeStamp, get_time_str(importDesc->dwTimeStamp));
832
833         printf("  Ordn  Name\n");
834
835         il = RVA(importDesc->pINT - offset, sizeof(DWORD));
836
837         if (!il)
838             printf("Can't grab thunk data, going to next imported DLL\n");
839         else
840         {
841             if (PE_nt_headers->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC)
842                 dump_image_thunk_data64((const IMAGE_THUNK_DATA64 *)il);
843             else
844                 dump_image_thunk_data32(il, offset);
845             printf("\n");
846         }
847         importDesc++;
848     }
849     printf("\n");
850 }
851
852 static  void    dump_dir_debug_dir(const IMAGE_DEBUG_DIRECTORY* idd, int idx)
853 {
854     const       char*   str;
855
856     printf("Directory %02u\n", idx + 1);
857     printf("  Characteristics:   %08X\n", idd->Characteristics);
858     printf("  TimeDateStamp:     %08X %s\n",
859            idd->TimeDateStamp, get_time_str(idd->TimeDateStamp));
860     printf("  Version            %u.%02u\n", idd->MajorVersion, idd->MinorVersion);
861     switch (idd->Type)
862     {
863     default:
864     case IMAGE_DEBUG_TYPE_UNKNOWN:      str = "UNKNOWN";        break;
865     case IMAGE_DEBUG_TYPE_COFF:         str = "COFF";           break;
866     case IMAGE_DEBUG_TYPE_CODEVIEW:     str = "CODEVIEW";       break;
867     case IMAGE_DEBUG_TYPE_FPO:          str = "FPO";            break;
868     case IMAGE_DEBUG_TYPE_MISC:         str = "MISC";           break;
869     case IMAGE_DEBUG_TYPE_EXCEPTION:    str = "EXCEPTION";      break;
870     case IMAGE_DEBUG_TYPE_FIXUP:        str = "FIXUP";          break;
871     case IMAGE_DEBUG_TYPE_OMAP_TO_SRC:  str = "OMAP_TO_SRC";    break;
872     case IMAGE_DEBUG_TYPE_OMAP_FROM_SRC:str = "OMAP_FROM_SRC";  break;
873     case IMAGE_DEBUG_TYPE_BORLAND:      str = "BORLAND";        break;
874     case IMAGE_DEBUG_TYPE_RESERVED10:   str = "RESERVED10";     break;
875     }
876     printf("  Type:              %u (%s)\n", idd->Type, str);
877     printf("  SizeOfData:        %u\n", idd->SizeOfData);
878     printf("  AddressOfRawData:  %08X\n", idd->AddressOfRawData);
879     printf("  PointerToRawData:  %08X\n", idd->PointerToRawData);
880
881     switch (idd->Type)
882     {
883     case IMAGE_DEBUG_TYPE_UNKNOWN:
884         break;
885     case IMAGE_DEBUG_TYPE_COFF:
886         dump_coff(idd->PointerToRawData, idd->SizeOfData,
887                   IMAGE_FIRST_SECTION(PE_nt_headers));
888         break;
889     case IMAGE_DEBUG_TYPE_CODEVIEW:
890         dump_codeview(idd->PointerToRawData, idd->SizeOfData);
891         break;
892     case IMAGE_DEBUG_TYPE_FPO:
893         dump_frame_pointer_omission(idd->PointerToRawData, idd->SizeOfData);
894         break;
895     case IMAGE_DEBUG_TYPE_MISC:
896     {
897         const IMAGE_DEBUG_MISC* misc = PRD(idd->PointerToRawData, idd->SizeOfData);
898         if (!misc) {printf("Can't get misc debug information\n"); break;}
899         printf("    DataType:          %u (%s)\n",
900                misc->DataType,
901                (misc->DataType == IMAGE_DEBUG_MISC_EXENAME) ? "Exe name" : "Unknown");
902         printf("    Length:            %u\n", misc->Length);
903         printf("    Unicode:           %s\n", misc->Unicode ? "Yes" : "No");
904         printf("    Data:              %s\n", misc->Data);
905     }
906     break;
907     case IMAGE_DEBUG_TYPE_EXCEPTION:
908         break;
909     case IMAGE_DEBUG_TYPE_FIXUP:
910         break;
911     case IMAGE_DEBUG_TYPE_OMAP_TO_SRC:
912         break;
913     case IMAGE_DEBUG_TYPE_OMAP_FROM_SRC:
914         break;
915     case IMAGE_DEBUG_TYPE_BORLAND:
916         break;
917     case IMAGE_DEBUG_TYPE_RESERVED10:
918         break;
919     }
920     printf("\n");
921 }
922
923 static void     dump_dir_debug(void)
924 {
925     unsigned                    nb_dbg, i;
926     const IMAGE_DEBUG_DIRECTORY*debugDir = get_dir_and_size(IMAGE_FILE_DEBUG_DIRECTORY, &nb_dbg);
927
928     nb_dbg /= sizeof(*debugDir);
929     if (!debugDir || !nb_dbg) return;
930
931     printf("Debug Table (%u directories)\n", nb_dbg);
932
933     for (i = 0; i < nb_dbg; i++)
934     {
935         dump_dir_debug_dir(debugDir, i);
936         debugDir++;
937     }
938     printf("\n");
939 }
940
941 static inline void print_clrflags(const char *title, DWORD value)
942 {
943     printf("  %-34s 0x%X\n", title, value);
944 #define X(f,s) if (value & f) printf("    %s\n", s)
945     X(COMIMAGE_FLAGS_ILONLY,           "ILONLY");
946     X(COMIMAGE_FLAGS_32BITREQUIRED,    "32BITREQUIRED");
947     X(COMIMAGE_FLAGS_IL_LIBRARY,       "IL_LIBRARY");
948     X(COMIMAGE_FLAGS_STRONGNAMESIGNED, "STRONGNAMESIGNED");
949     X(COMIMAGE_FLAGS_TRACKDEBUGDATA,   "TRACKDEBUGDATA");
950 #undef X
951 }
952
953 static inline void print_clrdirectory(const char *title, const IMAGE_DATA_DIRECTORY *dir)
954 {
955     printf("  %-23s rva: 0x%-8x  size: 0x%-8x\n", title, dir->VirtualAddress, dir->Size);
956 }
957
958 static void dump_dir_clr_header(void)
959 {
960     unsigned int size = 0;
961     const IMAGE_COR20_HEADER *dir = get_dir_and_size(IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR, &size);
962
963     if (!dir) return;
964
965     printf( "CLR Header\n" );
966     print_dword( "Header Size", dir->cb );
967     print_ver( "Required runtime version", dir->MajorRuntimeVersion, dir->MinorRuntimeVersion );
968     print_clrflags( "Flags", dir->Flags );
969     print_dword( "EntryPointToken", dir->EntryPointToken );
970     printf("\n");
971     printf( "CLR Data Directory\n" );
972     print_clrdirectory( "MetaData", &dir->MetaData );
973     print_clrdirectory( "Resources", &dir->Resources );
974     print_clrdirectory( "StrongNameSignature", &dir->StrongNameSignature );
975     print_clrdirectory( "CodeManagerTable", &dir->CodeManagerTable );
976     print_clrdirectory( "VTableFixups", &dir->VTableFixups );
977     print_clrdirectory( "ExportAddressTableJumps", &dir->ExportAddressTableJumps );
978     print_clrdirectory( "ManagedNativeHeader", &dir->ManagedNativeHeader );
979     printf("\n");
980 }
981
982 static void dump_dir_reloc(void)
983 {
984     unsigned int i, size = 0;
985     const USHORT *relocs;
986     const IMAGE_BASE_RELOCATION *rel = get_dir_and_size(IMAGE_DIRECTORY_ENTRY_BASERELOC, &size);
987     const IMAGE_BASE_RELOCATION *end = (const IMAGE_BASE_RELOCATION *)((const char *)rel + size);
988     static const char * const names[] =
989     {
990         "BASED_ABSOLUTE",
991         "BASED_HIGH",
992         "BASED_LOW",
993         "BASED_HIGHLOW",
994         "BASED_HIGHADJ",
995         "BASED_MIPS_JMPADDR",
996         "BASED_SECTION",
997         "BASED_REL",
998         "unknown 8",
999         "BASED_IA64_IMM64",
1000         "BASED_DIR64",
1001         "BASED_HIGH3ADJ",
1002         "unknown 12",
1003         "unknown 13",
1004         "unknown 14",
1005         "unknown 15"
1006     };
1007
1008     if (!rel) return;
1009
1010     printf( "Relocations\n" );
1011     while (rel < end - 1 && rel->SizeOfBlock)
1012     {
1013         printf( "  Page %x\n", rel->VirtualAddress );
1014         relocs = (const USHORT *)(rel + 1);
1015         i = (rel->SizeOfBlock - sizeof(*rel)) / sizeof(USHORT);
1016         while (i--)
1017         {
1018             USHORT offset = *relocs & 0xfff;
1019             int type = *relocs >> 12;
1020             printf( "    off %04x type %s\n", offset, names[type] );
1021             relocs++;
1022         }
1023         rel = (const IMAGE_BASE_RELOCATION *)relocs;
1024     }
1025     printf("\n");
1026 }
1027
1028 static void dump_dir_tls(void)
1029 {
1030     IMAGE_TLS_DIRECTORY64 dir;
1031     const DWORD *callbacks;
1032     const IMAGE_TLS_DIRECTORY32 *pdir = get_dir(IMAGE_FILE_THREAD_LOCAL_STORAGE);
1033
1034     if (!pdir) return;
1035
1036     if(PE_nt_headers->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC)
1037         memcpy(&dir, pdir, sizeof(dir));
1038     else
1039     {
1040         dir.StartAddressOfRawData = pdir->StartAddressOfRawData;
1041         dir.EndAddressOfRawData = pdir->EndAddressOfRawData;
1042         dir.AddressOfIndex = pdir->AddressOfIndex;
1043         dir.AddressOfCallBacks = pdir->AddressOfCallBacks;
1044         dir.SizeOfZeroFill = pdir->SizeOfZeroFill;
1045         dir.Characteristics = pdir->Characteristics;
1046     }
1047
1048     /* FIXME: This does not properly handle large images */
1049     printf( "Thread Local Storage\n" );
1050     printf( "  Raw data        %08x-%08x (data size %x zero fill size %x)\n",
1051             (DWORD)dir.StartAddressOfRawData, (DWORD)dir.EndAddressOfRawData,
1052             (DWORD)(dir.EndAddressOfRawData - dir.StartAddressOfRawData),
1053             (DWORD)dir.SizeOfZeroFill );
1054     printf( "  Index address   %08x\n", (DWORD)dir.AddressOfIndex );
1055     printf( "  Characteristics %08x\n", dir.Characteristics );
1056     printf( "  Callbacks       %08x -> {", (DWORD)dir.AddressOfCallBacks );
1057     if (dir.AddressOfCallBacks)
1058     {
1059         DWORD   addr = (DWORD)dir.AddressOfCallBacks - PE_nt_headers->OptionalHeader.ImageBase;
1060         while ((callbacks = RVA(addr, sizeof(DWORD))) && *callbacks)
1061         {
1062             printf( " %08x", *callbacks );
1063             addr += sizeof(DWORD);
1064         }
1065     }
1066     printf(" }\n\n");
1067 }
1068
1069 enum FileSig get_kind_dbg(void)
1070 {
1071     const WORD*                pw;
1072
1073     pw = PRD(0, sizeof(WORD));
1074     if (!pw) {printf("Can't get main signature, aborting\n"); return 0;}
1075
1076     if (*pw == 0x4944 /* "DI" */) return SIG_DBG;
1077     return SIG_UNKNOWN;
1078 }
1079
1080 void    dbg_dump(void)
1081 {
1082     const IMAGE_SEPARATE_DEBUG_HEADER*  separateDebugHead;
1083     unsigned                            nb_dbg;
1084     unsigned                            i;
1085     const IMAGE_DEBUG_DIRECTORY*        debugDir;
1086
1087     separateDebugHead = PRD(0, sizeof(*separateDebugHead));
1088     if (!separateDebugHead) {printf("Can't grab the separate header, aborting\n"); return;}
1089
1090     printf ("Signature:          %.2s (0x%4X)\n",
1091             (const char*)&separateDebugHead->Signature, separateDebugHead->Signature);
1092     printf ("Flags:              0x%04X\n", separateDebugHead->Flags);
1093     printf ("Machine:            0x%04X (%s)\n",
1094             separateDebugHead->Machine, get_machine_str(separateDebugHead->Machine));
1095     printf ("Characteristics:    0x%04X\n", separateDebugHead->Characteristics);
1096     printf ("TimeDateStamp:      0x%08X (%s)\n",
1097             separateDebugHead->TimeDateStamp, get_time_str(separateDebugHead->TimeDateStamp));
1098     printf ("CheckSum:           0x%08X\n", separateDebugHead->CheckSum);
1099     printf ("ImageBase:          0x%08X\n", separateDebugHead->ImageBase);
1100     printf ("SizeOfImage:        0x%08X\n", separateDebugHead->SizeOfImage);
1101     printf ("NumberOfSections:   0x%08X\n", separateDebugHead->NumberOfSections);
1102     printf ("ExportedNamesSize:  0x%08X\n", separateDebugHead->ExportedNamesSize);
1103     printf ("DebugDirectorySize: 0x%08X\n", separateDebugHead->DebugDirectorySize);
1104
1105     if (!PRD(sizeof(IMAGE_SEPARATE_DEBUG_HEADER),
1106              separateDebugHead->NumberOfSections * sizeof(IMAGE_SECTION_HEADER)))
1107     {printf("Can't get the sections, aborting\n"); return;}
1108
1109     dump_sections(separateDebugHead, separateDebugHead + 1, separateDebugHead->NumberOfSections);
1110
1111     nb_dbg = separateDebugHead->DebugDirectorySize / sizeof(IMAGE_DEBUG_DIRECTORY);
1112     debugDir = PRD(sizeof(IMAGE_SEPARATE_DEBUG_HEADER) +
1113                    separateDebugHead->NumberOfSections * sizeof(IMAGE_SECTION_HEADER) +
1114                    separateDebugHead->ExportedNamesSize,
1115                    nb_dbg * sizeof(IMAGE_DEBUG_DIRECTORY));
1116     if (!debugDir) {printf("Couldn't get the debug directory info, aborting\n");return;}
1117
1118     printf("Debug Table (%u directories)\n", nb_dbg);
1119
1120     for (i = 0; i < nb_dbg; i++)
1121     {
1122         dump_dir_debug_dir(debugDir, i);
1123         debugDir++;
1124     }
1125 }
1126
1127 static const char *get_resource_type( unsigned int id )
1128 {
1129     static const char * const types[] =
1130     {
1131         NULL,
1132         "CURSOR",
1133         "BITMAP",
1134         "ICON",
1135         "MENU",
1136         "DIALOG",
1137         "STRING",
1138         "FONTDIR",
1139         "FONT",
1140         "ACCELERATOR",
1141         "RCDATA",
1142         "MESSAGETABLE",
1143         "GROUP_CURSOR",
1144         NULL,
1145         "GROUP_ICON",
1146         NULL,
1147         "VERSION",
1148         "DLGINCLUDE",
1149         NULL,
1150         "PLUGPLAY",
1151         "VXD",
1152         "ANICURSOR",
1153         "ANIICON",
1154         "HTML",
1155         "RT_MANIFEST"
1156     };
1157
1158     if ((size_t)id < sizeof(types)/sizeof(types[0])) return types[id];
1159     return NULL;
1160 }
1161
1162 /* dump an ASCII string with proper escaping */
1163 static int dump_strA( const unsigned char *str, size_t len )
1164 {
1165     static const char escapes[32] = ".......abtnvfr.............e....";
1166     char buffer[256];
1167     char *pos = buffer;
1168     int count = 0;
1169
1170     for (; len; str++, len--)
1171     {
1172         if (pos > buffer + sizeof(buffer) - 8)
1173         {
1174             fwrite( buffer, pos - buffer, 1, stdout );
1175             count += pos - buffer;
1176             pos = buffer;
1177         }
1178         if (*str > 127)  /* hex escape */
1179         {
1180             pos += sprintf( pos, "\\x%02x", *str );
1181             continue;
1182         }
1183         if (*str < 32)  /* octal or C escape */
1184         {
1185             if (!*str && len == 1) continue;  /* do not output terminating NULL */
1186             if (escapes[*str] != '.')
1187                 pos += sprintf( pos, "\\%c", escapes[*str] );
1188             else if (len > 1 && str[1] >= '0' && str[1] <= '7')
1189                 pos += sprintf( pos, "\\%03o", *str );
1190             else
1191                 pos += sprintf( pos, "\\%o", *str );
1192             continue;
1193         }
1194         if (*str == '\\') *pos++ = '\\';
1195         *pos++ = *str;
1196     }
1197     fwrite( buffer, pos - buffer, 1, stdout );
1198     count += pos - buffer;
1199     return count;
1200 }
1201
1202 /* dump a Unicode string with proper escaping */
1203 static int dump_strW( const WCHAR *str, size_t len )
1204 {
1205     static const char escapes[32] = ".......abtnvfr.............e....";
1206     char buffer[256];
1207     char *pos = buffer;
1208     int count = 0;
1209
1210     for (; len; str++, len--)
1211     {
1212         if (pos > buffer + sizeof(buffer) - 8)
1213         {
1214             fwrite( buffer, pos - buffer, 1, stdout );
1215             count += pos - buffer;
1216             pos = buffer;
1217         }
1218         if (*str > 127)  /* hex escape */
1219         {
1220             if (len > 1 && str[1] < 128 && isxdigit((char)str[1]))
1221                 pos += sprintf( pos, "\\x%04x", *str );
1222             else
1223                 pos += sprintf( pos, "\\x%x", *str );
1224             continue;
1225         }
1226         if (*str < 32)  /* octal or C escape */
1227         {
1228             if (!*str && len == 1) continue;  /* do not output terminating NULL */
1229             if (escapes[*str] != '.')
1230                 pos += sprintf( pos, "\\%c", escapes[*str] );
1231             else if (len > 1 && str[1] >= '0' && str[1] <= '7')
1232                 pos += sprintf( pos, "\\%03o", *str );
1233             else
1234                 pos += sprintf( pos, "\\%o", *str );
1235             continue;
1236         }
1237         if (*str == '\\') *pos++ = '\\';
1238         *pos++ = *str;
1239     }
1240     fwrite( buffer, pos - buffer, 1, stdout );
1241     count += pos - buffer;
1242     return count;
1243 }
1244
1245 /* dump data for a STRING resource */
1246 static void dump_string_data( const WCHAR *ptr, unsigned int size, unsigned int id, const char *prefix )
1247 {
1248     int i;
1249
1250     for (i = 0; i < 16 && size; i++)
1251     {
1252         unsigned len = *ptr++;
1253
1254         if (len >= size)
1255         {
1256             len = size;
1257             size = 0;
1258         }
1259         else size -= len + 1;
1260
1261         if (len)
1262         {
1263             printf( "%s%04x \"", prefix, (id - 1) * 16 + i );
1264             dump_strW( ptr, len );
1265             printf( "\"\n" );
1266             ptr += len;
1267         }
1268     }
1269 }
1270
1271 /* dump data for a MESSAGETABLE resource */
1272 static void dump_msgtable_data( const void *ptr, unsigned int size, unsigned int id, const char *prefix )
1273 {
1274     const MESSAGE_RESOURCE_DATA *data = ptr;
1275     const MESSAGE_RESOURCE_BLOCK *block = data->Blocks;
1276     unsigned i, j;
1277
1278     for (i = 0; i < data->NumberOfBlocks; i++, block++)
1279     {
1280         const MESSAGE_RESOURCE_ENTRY *entry;
1281
1282         entry = (const MESSAGE_RESOURCE_ENTRY *)((const char *)data + block->OffsetToEntries);
1283         for (j = block->LowId; j <= block->HighId; j++)
1284         {
1285             if (entry->Flags & MESSAGE_RESOURCE_UNICODE)
1286             {
1287                 const WCHAR *str = (const WCHAR *)entry->Text;
1288                 printf( "%s%08x L\"", prefix, j );
1289                 dump_strW( str, strlenW(str) );
1290                 printf( "\"\n" );
1291             }
1292             else
1293             {
1294                 const char *str = (const char *) entry->Text;
1295                 printf( "%s%08x \"", prefix, j );
1296                 dump_strA( entry->Text, strlen(str) );
1297                 printf( "\"\n" );
1298             }
1299             entry = (const MESSAGE_RESOURCE_ENTRY *)((const char *)entry + entry->Length);
1300         }
1301     }
1302 }
1303
1304 static void dump_dir_resource(void)
1305 {
1306     const IMAGE_RESOURCE_DIRECTORY *root = get_dir(IMAGE_FILE_RESOURCE_DIRECTORY);
1307     const IMAGE_RESOURCE_DIRECTORY *namedir;
1308     const IMAGE_RESOURCE_DIRECTORY *langdir;
1309     const IMAGE_RESOURCE_DIRECTORY_ENTRY *e1, *e2, *e3;
1310     const IMAGE_RESOURCE_DIR_STRING_U *string;
1311     const IMAGE_RESOURCE_DATA_ENTRY *data;
1312     int i, j, k;
1313
1314     if (!root) return;
1315
1316     printf( "Resources:" );
1317
1318     for (i = 0; i< root->NumberOfNamedEntries + root->NumberOfIdEntries; i++)
1319     {
1320         e1 = (const IMAGE_RESOURCE_DIRECTORY_ENTRY*)(root + 1) + i;
1321         namedir = (const IMAGE_RESOURCE_DIRECTORY *)((const char *)root + e1->u2.s3.OffsetToDirectory);
1322         for (j = 0; j < namedir->NumberOfNamedEntries + namedir->NumberOfIdEntries; j++)
1323         {
1324             e2 = (const IMAGE_RESOURCE_DIRECTORY_ENTRY*)(namedir + 1) + j;
1325             langdir = (const IMAGE_RESOURCE_DIRECTORY *)((const char *)root + e2->u2.s3.OffsetToDirectory);
1326             for (k = 0; k < langdir->NumberOfNamedEntries + langdir->NumberOfIdEntries; k++)
1327             {
1328                 e3 = (const IMAGE_RESOURCE_DIRECTORY_ENTRY*)(langdir + 1) + k;
1329
1330                 printf( "\n  " );
1331                 if (e1->u1.s1.NameIsString)
1332                 {
1333                     string = (const IMAGE_RESOURCE_DIR_STRING_U*)((const char *)root + e1->u1.s1.NameOffset);
1334                     dump_unicode_str( string->NameString, string->Length );
1335                 }
1336                 else
1337                 {
1338                     const char *type = get_resource_type( e1->u1.s2.Id );
1339                     if (type) printf( "%s", type );
1340                     else printf( "%04x", e1->u1.s2.Id );
1341                 }
1342
1343                 printf( " Name=" );
1344                 if (e2->u1.s1.NameIsString)
1345                 {
1346                     string = (const IMAGE_RESOURCE_DIR_STRING_U*) ((const char *)root + e2->u1.s1.NameOffset);
1347                     dump_unicode_str( string->NameString, string->Length );
1348                 }
1349                 else
1350                     printf( "%04x", e2->u1.s2.Id );
1351
1352                 printf( " Language=%04x:\n", e3->u1.s2.Id );
1353                 data = (const IMAGE_RESOURCE_DATA_ENTRY *)((const char *)root + e3->u2.OffsetToData);
1354                 if (e1->u1.s1.NameIsString)
1355                 {
1356                     dump_data( RVA( data->OffsetToData, data->Size ), data->Size, "    " );
1357                 }
1358                 else switch(e1->u1.s2.Id)
1359                 {
1360                 case 6:
1361                     dump_string_data( RVA( data->OffsetToData, data->Size ), data->Size,
1362                                       e2->u1.s2.Id, "    " );
1363                     break;
1364                 case 11:
1365                     dump_msgtable_data( RVA( data->OffsetToData, data->Size ), data->Size,
1366                                         e2->u1.s2.Id, "    " );
1367                     break;
1368                 default:
1369                     dump_data( RVA( data->OffsetToData, data->Size ), data->Size, "    " );
1370                     break;
1371                 }
1372             }
1373         }
1374     }
1375     printf( "\n\n" );
1376 }
1377
1378 static void dump_debug(void)
1379 {
1380     const char* stabs = NULL;
1381     unsigned    szstabs = 0;
1382     const char* stabstr = NULL;
1383     unsigned    szstr = 0;
1384     unsigned    i;
1385     const IMAGE_SECTION_HEADER* sectHead;
1386
1387     sectHead = IMAGE_FIRST_SECTION(PE_nt_headers);
1388
1389     for (i = 0; i < PE_nt_headers->FileHeader.NumberOfSections; i++, sectHead++)
1390     {
1391         if (!strcmp((const char *)sectHead->Name, ".stab"))
1392         {
1393             stabs = RVA(sectHead->VirtualAddress, sectHead->Misc.VirtualSize); 
1394             szstabs = sectHead->Misc.VirtualSize;
1395         }
1396         if (!strncmp((const char *)sectHead->Name, ".stabstr", 8))
1397         {
1398             stabstr = RVA(sectHead->VirtualAddress, sectHead->Misc.VirtualSize);
1399             szstr = sectHead->Misc.VirtualSize;
1400         }
1401     }
1402     if (stabs && stabstr)
1403         dump_stabs(stabs, szstabs, stabstr, szstr);
1404 }
1405
1406 static void dump_symbol_table(void)
1407 {
1408     const IMAGE_SYMBOL* sym;
1409     int                 numsym;
1410
1411     numsym = PE_nt_headers->FileHeader.NumberOfSymbols;
1412     if (!PE_nt_headers->FileHeader.PointerToSymbolTable || !numsym)
1413         return;
1414     sym = PRD(PE_nt_headers->FileHeader.PointerToSymbolTable,
1415                                    sizeof(*sym) * numsym);
1416     if (!sym) return;
1417
1418     dump_coff_symbol_table(sym, numsym, IMAGE_FIRST_SECTION(PE_nt_headers));
1419 }
1420
1421 enum FileSig get_kind_exec(void)
1422 {
1423     const WORD*                pw;
1424     const DWORD*               pdw;
1425     const IMAGE_DOS_HEADER*    dh;
1426
1427     pw = PRD(0, sizeof(WORD));
1428     if (!pw) {printf("Can't get main signature, aborting\n"); return 0;}
1429
1430     if (*pw != IMAGE_DOS_SIGNATURE) return SIG_UNKNOWN;
1431
1432     if ((dh = PRD(0, sizeof(IMAGE_DOS_HEADER))))
1433     {
1434         /* the signature is the first DWORD */
1435         pdw = PRD(dh->e_lfanew, sizeof(DWORD));
1436         if (pdw)
1437         {
1438             if (*pdw == IMAGE_NT_SIGNATURE)                     return SIG_PE;
1439             if (*(const WORD *)pdw == IMAGE_OS2_SIGNATURE)      return SIG_NE;
1440             if (*(const WORD *)pdw == IMAGE_VXD_SIGNATURE)      return SIG_LE;
1441         }
1442         return SIG_DOS;
1443     }
1444     return SIG_UNKNOWN;
1445 }
1446
1447 void pe_dump(void)
1448 {
1449     int all = (globals.dumpsect != NULL) && strcmp(globals.dumpsect, "ALL") == 0;
1450
1451     PE_nt_headers = get_nt_header();
1452     if (is_fake_dll()) printf( "*** This is a Wine fake DLL ***\n\n" );
1453
1454     if (globals.do_dumpheader)
1455     {
1456         dump_pe_header();
1457         /* FIXME: should check ptr */
1458         dump_sections(PRD(0, 1), IMAGE_FIRST_SECTION(PE_nt_headers),
1459                       PE_nt_headers->FileHeader.NumberOfSections);
1460     }
1461     else if (!globals.dumpsect)
1462     {
1463         /* show at least something here */
1464         dump_pe_header();
1465     }
1466
1467     if (globals.dumpsect)
1468     {
1469         if (all || !strcmp(globals.dumpsect, "import"))
1470         {
1471             dump_dir_imported_functions();
1472             dump_dir_delay_imported_functions();
1473         }
1474         if (all || !strcmp(globals.dumpsect, "export"))
1475             dump_dir_exported_functions();
1476         if (all || !strcmp(globals.dumpsect, "debug"))
1477             dump_dir_debug();
1478         if (all || !strcmp(globals.dumpsect, "resource"))
1479             dump_dir_resource();
1480         if (all || !strcmp(globals.dumpsect, "tls"))
1481             dump_dir_tls();
1482         if (all || !strcmp(globals.dumpsect, "clr"))
1483             dump_dir_clr_header();
1484         if (all || !strcmp(globals.dumpsect, "reloc"))
1485             dump_dir_reloc();
1486         if (all || !strcmp(globals.dumpsect, "except"))
1487             dump_dir_exceptions();
1488     }
1489     if (globals.do_symbol_table)
1490         dump_symbol_table();
1491     if (globals.do_debug)
1492         dump_debug();
1493 }
1494
1495 typedef struct _dll_symbol {
1496     size_t      ordinal;
1497     char       *symbol;
1498 } dll_symbol;
1499
1500 static dll_symbol *dll_symbols = NULL;
1501 static dll_symbol *dll_current_symbol = NULL;
1502
1503 /* Compare symbols by ordinal for qsort */
1504 static int symbol_cmp(const void *left, const void *right)
1505 {
1506     return ((const dll_symbol *)left)->ordinal > ((const dll_symbol *)right)->ordinal;
1507 }
1508
1509 /*******************************************************************
1510  *         dll_close
1511  *
1512  * Free resources used by DLL
1513  */
1514 /* FIXME: Not used yet
1515 static void dll_close (void)
1516 {
1517     dll_symbol* ds;
1518
1519     if (!dll_symbols) {
1520         fatal("No symbols");
1521     }
1522     for (ds = dll_symbols; ds->symbol; ds++)
1523         free(ds->symbol);
1524     free (dll_symbols);
1525     dll_symbols = NULL;
1526 }
1527 */
1528
1529 static  void    do_grab_sym( void )
1530 {
1531     const IMAGE_EXPORT_DIRECTORY*exportDir;
1532     unsigned                    i, j;
1533     const DWORD*                pName;
1534     const DWORD*                pFunc;
1535     const WORD*                 pOrdl;
1536     const char*                 ptr;
1537     DWORD*                      map;
1538
1539     PE_nt_headers = get_nt_header();
1540     if (!(exportDir = get_dir(IMAGE_FILE_EXPORT_DIRECTORY))) return;
1541
1542     pName = RVA(exportDir->AddressOfNames, exportDir->NumberOfNames * sizeof(DWORD));
1543     if (!pName) {printf("Can't grab functions' name table\n"); return;}
1544     pOrdl = RVA(exportDir->AddressOfNameOrdinals, exportDir->NumberOfNames * sizeof(WORD));
1545     if (!pOrdl) {printf("Can't grab functions' ordinal table\n"); return;}
1546     pFunc = RVA(exportDir->AddressOfFunctions, exportDir->NumberOfFunctions * sizeof(DWORD));
1547     if (!pFunc) {printf("Can't grab functions' address table\n"); return;}
1548
1549     /* dll_close(); */
1550
1551     if (!(dll_symbols = malloc((exportDir->NumberOfFunctions + 1) * sizeof(dll_symbol))))
1552         fatal ("Out of memory");
1553
1554     /* bit map of used funcs */
1555     map = calloc(((exportDir->NumberOfFunctions + 31) & ~31) / 32, sizeof(DWORD));
1556     if (!map) fatal("no memory");
1557
1558     for (j = 0; j < exportDir->NumberOfNames; j++, pOrdl++)
1559     {
1560         map[*pOrdl / 32] |= 1 << (*pOrdl % 32);
1561         ptr = RVA(*pName++, sizeof(DWORD));
1562         if (!ptr) ptr = "cant_get_function";
1563         dll_symbols[j].symbol = strdup(ptr);
1564         dll_symbols[j].ordinal = exportDir->Base + *pOrdl;
1565         assert(dll_symbols[j].symbol);
1566     }
1567
1568     for (i = 0; i < exportDir->NumberOfFunctions; i++)
1569     {
1570         if (pFunc[i] && !(map[i / 32] & (1 << (i % 32))))
1571         {
1572             char ordinal_text[256];
1573             /* Ordinal only entry */
1574             snprintf (ordinal_text, sizeof(ordinal_text), "%s_%u",
1575                       globals.forward_dll ? globals.forward_dll : OUTPUT_UC_DLL_NAME,
1576                       exportDir->Base + i);
1577             str_toupper(ordinal_text);
1578             dll_symbols[j].symbol = strdup(ordinal_text);
1579             assert(dll_symbols[j].symbol);
1580             dll_symbols[j].ordinal = exportDir->Base + i;
1581             j++;
1582             assert(j <= exportDir->NumberOfFunctions);
1583         }
1584     }
1585     free(map);
1586
1587     if (NORMAL)
1588         printf("%u named symbols in DLL, %u total, %d unique (ordinal base = %d)\n",
1589                exportDir->NumberOfNames, exportDir->NumberOfFunctions, j, exportDir->Base);
1590
1591     qsort( dll_symbols, j, sizeof(dll_symbol), symbol_cmp );
1592
1593     dll_symbols[j].symbol = NULL;
1594
1595     dll_current_symbol = dll_symbols;
1596 }
1597
1598 /*******************************************************************
1599  *         dll_open
1600  *
1601  * Open a DLL and read in exported symbols
1602  */
1603 int dll_open (const char *dll_name)
1604 {
1605     return dump_analysis(dll_name, do_grab_sym, SIG_PE);
1606 }
1607
1608 /*******************************************************************
1609  *         dll_next_symbol
1610  *
1611  * Get next exported symbol from dll
1612  */
1613 int dll_next_symbol (parsed_symbol * sym)
1614 {
1615     if (!dll_current_symbol || !dll_current_symbol->symbol)
1616        return 1;
1617      assert (dll_symbols);
1618     sym->symbol = strdup (dll_current_symbol->symbol);
1619     sym->ordinal = dll_current_symbol->ordinal;
1620     dll_current_symbol++;
1621     return 0;
1622 }