Some dumb fixes.
[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    do_dump(void)
570 {
571     int all = (globals.dumpsect != NULL) && strcmp(globals.dumpsect, "ALL") == 0;
572
573     if (globals.do_dumpheader)
574     {
575         dump_pe_header();
576         /* FIX%E: should check ptr */
577         dump_sections((char*)nt_headers + sizeof(DWORD) + 
578                       sizeof(IMAGE_FILE_HEADER) + nt_headers->FileHeader.SizeOfOptionalHeader,
579                       nt_headers->FileHeader.NumberOfSections);
580     }
581     else if (!globals.dumpsect)
582     {
583         /* show at least something here */
584         dump_pe_header();
585     }
586
587     if (globals.dumpsect)
588     {
589         if (all || !strcmp(globals.dumpsect, "import"))
590             dump_dir_imported_functions();
591         if (all || !strcmp(globals.dumpsect, "export"))
592             dump_dir_exported_functions();
593         if (all || !strcmp(globals.dumpsect, "debug"))
594             dump_dir_debug();
595 #if 0
596         /* FIXME: not implemented yet */
597         if (all || !strcmp(globals.dumpsect, "resource"))
598             dump_dir_resource();
599         if (all || !strcmp(globals.dumpsect, "reloc"))
600             dump_dir_reloc();
601 #endif
602     }
603 }
604
605 static  enum FileSig    check_headers(void)
606 {
607     WORD*               pw;
608     DWORD*              pdw;
609     IMAGE_DOS_HEADER*   dh;
610     enum FileSig        sig;
611     
612     pw = PRD(0, sizeof(WORD));
613     if (!pw) {printf("Can't get main signature, aborting\n"); return 0;}
614     
615     switch (*pw)
616     {
617     case IMAGE_DOS_SIGNATURE:   
618         sig = SIG_DOS;
619         dh = PRD(0, sizeof(IMAGE_DOS_HEADER));
620         if (dh && dh->e_lfanew >= sizeof(*dh)) /* reasonable DOS header ? */
621         {
622             /* the signature is the first DWORD */
623             pdw = PRD(dh->e_lfanew, sizeof(DWORD));
624             if (pdw)
625             {
626                 if (*pdw == IMAGE_NT_SIGNATURE)
627                 {
628                     nt_headers = PRD(dh->e_lfanew, sizeof(DWORD));
629                     sig = SIG_PE;
630                 }
631                 else
632                 {
633                     printf("No PE Signature found\n");
634                 }
635             }
636             else
637             {
638                 printf("Can't get the extented signature, aborting\n"); 
639             }
640         }
641         break;
642     case 0x4944: /* "DI" */
643         sig = SIG_DBG;
644         break;
645     default:
646         printf("No known main signature (%.2s/%x), aborting\n", (char*)pw, *pw); 
647         sig = SIG_UNKNOWN;
648     }
649     
650     return sig;
651 }
652
653 int pe_analysis(const char* name, void (*fn)(void), enum FileSig wanted_sig)
654 {
655     int                 fd;
656     enum FileSig        effective_sig;
657     int                 ret = 1;
658     struct stat         s;
659
660     setbuf(stdout, NULL);
661     
662     fd = open(name, O_RDONLY);
663     if (fd == -1) fatal("Can't open file");
664     
665     if (fstat(fd, &s) < 0) fatal("Can't get size");
666     total_len = s.st_size;
667     
668     base = mmap(NULL, total_len, PROT_READ, MAP_PRIVATE, fd, 0);
669     if (base == (void*)-1) fatal("Can't map file");
670     
671     effective_sig = check_headers();
672     
673     if (effective_sig == SIG_UNKNOWN)
674     {
675         printf("Can't get a recognized file signature, aborting\n");
676         ret = 0;
677     }
678     else if (wanted_sig == SIG_UNKNOWN || wanted_sig == effective_sig)
679     {
680         switch (effective_sig)
681         {
682         case SIG_UNKNOWN: /* shouldn't happen... */
683             ret = 0; break;
684         case SIG_PE:
685             printf("Contents of \"%s\": %ld bytes\n\n", name, total_len);
686             (*fn)();
687             break;
688         case SIG_DBG:
689             dump_separate_dbg();
690             break;
691         case SIG_DOS:
692             ret = 0; break;
693         }
694     }
695     else
696     {
697         printf("Can't get a suitable file signature, aborting\n");
698         ret = 0;
699     }
700     
701     if (ret) printf("Done dumping %s\n", name);
702     munmap(base, total_len);
703     close(fd);
704     
705     return ret;
706 }
707
708 void    dump_file(const char* name)
709 {
710     pe_analysis(name, do_dump, SIG_UNKNOWN);
711 }
712
713 #if 0
714 int     main(int argc, char* argv[])
715 {
716     if (argc != 2) fatal("usage");
717     pe_analysis(argv[1], do_dump);
718 }
719 #endif
720
721 typedef struct _dll_symbol {
722     size_t      ordinal;
723     char       *symbol;
724 } dll_symbol;
725
726 static dll_symbol *dll_symbols = NULL;
727 static dll_symbol *dll_current_symbol = NULL;
728
729 /* Compare symbols by ordinal for qsort */
730 static int symbol_cmp(const void *left, const void *right)
731 {
732     return ((dll_symbol *)left)->ordinal > ((dll_symbol *)right)->ordinal;
733 }
734
735 /*******************************************************************
736  *         dll_close
737  *
738  * Free resources used by DLL
739  */
740 static void dll_close (void)
741 {
742     dll_symbol* ds;
743     
744     for (ds = dll_symbols; ds->symbol; ds++)
745         free(ds->symbol);
746     free (dll_symbols);
747     dll_symbols = NULL;
748 }
749
750 static  void    do_grab_sym(void)
751 {
752     IMAGE_EXPORT_DIRECTORY      *exportDir = get_dir(IMAGE_FILE_EXPORT_DIRECTORY);
753     unsigned                    i;
754     DWORD*                      pName;
755     DWORD*                      pFunc;
756     WORD*                       pOrdl;
757     char*                       ptr;
758     DWORD*                      map;
759     
760     if (!exportDir) return;
761     
762     pName = RVA(exportDir->AddressOfNames, exportDir->NumberOfNames * sizeof(DWORD));
763     if (!pName) {printf("Can't grab functions' name table\n"); return;}
764     pOrdl = RVA(exportDir->AddressOfNameOrdinals, exportDir->NumberOfNames * sizeof(WORD));
765     if (!pOrdl) {printf("Can't grab functions' ordinal table\n"); return;}
766     
767     dll_close();
768     
769     if (!(dll_symbols = (dll_symbol *) malloc((exportDir->NumberOfFunctions + 1) * 
770                                               sizeof (dll_symbol))))
771         fatal ("Out of memory");
772     if (exportDir->AddressOfFunctions != exportDir->NumberOfNames || exportDir->Base > 1)
773         globals.do_ordinals = 1;
774     
775     /* bit map of used funcs */
776     map = calloc(((exportDir->NumberOfFunctions + 31) & ~31) / 32, sizeof(DWORD));
777     if (!map) fatal("no memory");
778     
779     for (i = 0; i < exportDir->NumberOfNames; i++)
780     {
781         map[*pOrdl / 32] |= 1 << (*pOrdl % 32);
782         ptr = RVA(*pName++, sizeof(DWORD));
783         if (!ptr) ptr = "cant_get_function";
784         dll_symbols[i].symbol = strdup(ptr);
785         assert(dll_symbols[i].symbol);
786     }
787     pFunc = RVA(exportDir->AddressOfFunctions, exportDir->NumberOfFunctions * sizeof(DWORD));
788     if (!pFunc) {printf("Can't grab functions' address table\n"); return;}
789     for (i = 0; i < exportDir->NumberOfFunctions; i++)
790     {
791         if (!(map[i / 32] & (1 << (i % 32))))
792         {
793             char ordinal_text[256];
794             /* Ordinal only entry */
795             snprintf (ordinal_text, sizeof(ordinal_text), "%s_%lu",
796                       globals.forward_dll ? globals.forward_dll : OUTPUT_UC_DLL_NAME,
797                       exportDir->Base + i);
798             str_toupper(ordinal_text);
799             dll_symbols[i].symbol = strdup(ordinal_text);
800             assert(dll_symbols[i].symbol);
801             dll_symbols[i].ordinal = exportDir->Base + i;
802         }
803     }
804     free(map);
805     
806     if (NORMAL)
807         printf("%lu named symbols in DLL, %lu total\n", 
808                exportDir->NumberOfNames, exportDir->NumberOfFunctions);
809     
810     qsort( dll_symbols, exportDir->NumberOfFunctions, sizeof(dll_symbol), symbol_cmp );
811     
812     dll_symbols[exportDir->NumberOfFunctions].symbol = NULL;
813     
814     dll_current_symbol = dll_symbols;
815     
816     /* Set DLL output names */
817     if ((ptr = strrchr (globals.input_name, '/')))
818         globals.input_name = ptr + 1; /* Strip path */
819     
820     OUTPUT_UC_DLL_NAME = str_toupper( strdup (OUTPUT_DLL_NAME));
821 }
822
823 /*******************************************************************
824  *         dll_open
825  *
826  * Open a DLL and read in exported symbols
827  */
828 void  dll_open (const char *dll_name)
829 {
830     pe_analysis(dll_name, do_grab_sym, SIG_PE);
831 }
832
833 /*******************************************************************
834  *         dll_next_symbol
835  *
836  * Get next exported symbol from dll
837  */
838 int dll_next_symbol (parsed_symbol * sym)
839 {
840     if (!dll_current_symbol)
841         return 1;
842     
843     assert (dll_symbols);
844     
845     sym->symbol = strdup (dll_current_symbol->symbol);
846     sym->ordinal = dll_current_symbol->ordinal;
847     dll_current_symbol++;
848     return 0;
849 }