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