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