Constify wcmd.
[wine/testsucceed.git] / tools / winedump / pe.c
blobf04287735350351cc73d94cab10259bb120ab3a1
1 /*
2 * PE dumping utility
4 * Copyright 2001 Eric Pouech
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.
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.
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
21 #include "config.h"
22 #include "wine/port.h"
24 #include <stdlib.h>
25 #include <stdarg.h>
26 #include <stdio.h>
27 #ifdef HAVE_UNISTD_H
28 # include <unistd.h>
29 #endif
30 #include <time.h>
31 #ifdef HAVE_SYS_TYPES_H
32 # include <sys/types.h>
33 #endif
34 #ifdef HAVE_SYS_STAT_H
35 # include <sys/stat.h>
36 #endif
37 #ifdef HAVE_SYS_MMAN_H
38 #include <sys/mman.h>
39 #endif
40 #include <fcntl.h>
42 #define NONAMELESSUNION
43 #define NONAMELESSSTRUCT
44 #include "windef.h"
45 #include "winbase.h"
46 #include "winedump.h"
47 #include "pe.h"
49 static IMAGE_NT_HEADERS* PE_nt_headers;
51 static const char* get_machine_str(DWORD mach)
53 switch (mach)
55 case IMAGE_FILE_MACHINE_UNKNOWN: return "Unknown";
56 case IMAGE_FILE_MACHINE_I860: return "i860";
57 case IMAGE_FILE_MACHINE_I386: return "i386";
58 case IMAGE_FILE_MACHINE_R3000: return "R3000";
59 case IMAGE_FILE_MACHINE_R4000: return "R4000";
60 case IMAGE_FILE_MACHINE_R10000: return "R10000";
61 case IMAGE_FILE_MACHINE_ALPHA: return "Alpha";
62 case IMAGE_FILE_MACHINE_POWERPC: return "PowerPC";
64 return "???";
67 static void* RVA(unsigned long rva, unsigned long len)
69 IMAGE_SECTION_HEADER* sectHead;
70 int i;
72 if (rva == 0) return NULL;
74 sectHead = (IMAGE_SECTION_HEADER*)((char*)PE_nt_headers + sizeof(DWORD) +
75 sizeof(IMAGE_FILE_HEADER) +
76 PE_nt_headers->FileHeader.SizeOfOptionalHeader);
78 for (i = PE_nt_headers->FileHeader.NumberOfSections - 1; i >= 0; i--)
80 if (sectHead[i].VirtualAddress <= rva &&
81 rva + len <= (DWORD)sectHead[i].VirtualAddress + sectHead[i].SizeOfRawData)
83 /* return image import directory offset */
84 return PRD(sectHead[i].PointerToRawData + rva - sectHead[i].VirtualAddress, len);
88 return NULL;
91 static void* get_dir(unsigned idx)
93 if (idx >= PE_nt_headers->OptionalHeader.NumberOfRvaAndSizes)
94 return NULL;
95 return RVA(PE_nt_headers->OptionalHeader.DataDirectory[idx].VirtualAddress,
96 PE_nt_headers->OptionalHeader.DataDirectory[idx].Size);
99 static void *get_dir_and_size(unsigned int idx, unsigned int *size)
101 if (idx >= PE_nt_headers->OptionalHeader.NumberOfRvaAndSizes)
102 return NULL;
103 *size = PE_nt_headers->OptionalHeader.DataDirectory[idx].Size;
104 return RVA(PE_nt_headers->OptionalHeader.DataDirectory[idx].VirtualAddress, *size);
107 static const char* DirectoryNames[16] = {
108 "EXPORT", "IMPORT", "RESOURCE", "EXCEPTION",
109 "SECURITY", "BASERELOC", "DEBUG", "ARCHITECTURE",
110 "GLOBALPTR", "TLS", "LOAD_CONFIG", "Bound IAT",
111 "IAT", "Delay IAT", "COM Descript", ""
114 static void dump_pe_header(void)
116 const char *str;
117 IMAGE_FILE_HEADER *fileHeader;
118 IMAGE_OPTIONAL_HEADER *optionalHeader;
119 unsigned i;
121 printf("File Header\n");
122 fileHeader = &PE_nt_headers->FileHeader;
124 printf(" Machine: %04X (%s)\n",
125 fileHeader->Machine, get_machine_str(fileHeader->Machine));
126 printf(" Number of Sections: %d\n", fileHeader->NumberOfSections);
127 printf(" TimeDateStamp: %08lX (%s) offset %lu\n",
128 fileHeader->TimeDateStamp, get_time_str(fileHeader->TimeDateStamp),
129 Offset(&(fileHeader->TimeDateStamp)));
130 printf(" PointerToSymbolTable: %08lX\n", fileHeader->PointerToSymbolTable);
131 printf(" NumberOfSymbols: %08lX\n", fileHeader->NumberOfSymbols);
132 printf(" SizeOfOptionalHeader: %04X\n", fileHeader->SizeOfOptionalHeader);
133 printf(" Characteristics: %04X\n", fileHeader->Characteristics);
134 #define X(f,s) if (fileHeader->Characteristics & f) printf(" %s\n", s)
135 X(IMAGE_FILE_RELOCS_STRIPPED, "RELOCS_STRIPPED");
136 X(IMAGE_FILE_EXECUTABLE_IMAGE, "EXECUTABLE_IMAGE");
137 X(IMAGE_FILE_LINE_NUMS_STRIPPED, "LINE_NUMS_STRIPPED");
138 X(IMAGE_FILE_LOCAL_SYMS_STRIPPED, "LOCAL_SYMS_STRIPPED");
139 X(IMAGE_FILE_16BIT_MACHINE, "16BIT_MACHINE");
140 X(IMAGE_FILE_BYTES_REVERSED_LO, "BYTES_REVERSED_LO");
141 X(IMAGE_FILE_32BIT_MACHINE, "32BIT_MACHINE");
142 X(IMAGE_FILE_DEBUG_STRIPPED, "DEBUG_STRIPPED");
143 X(IMAGE_FILE_SYSTEM, "SYSTEM");
144 X(IMAGE_FILE_DLL, "DLL");
145 X(IMAGE_FILE_BYTES_REVERSED_HI, "BYTES_REVERSED_HI");
146 #undef X
147 printf("\n");
149 /* hope we have the right size */
150 printf("Optional Header\n");
151 optionalHeader = &PE_nt_headers->OptionalHeader;
152 printf(" Magic 0x%-4X %u\n",
153 optionalHeader->Magic, optionalHeader->Magic);
154 printf(" linker version %u.%02u\n",
155 optionalHeader->MajorLinkerVersion, optionalHeader->MinorLinkerVersion);
156 printf(" size of code 0x%-8lx %lu\n",
157 optionalHeader->SizeOfCode, optionalHeader->SizeOfCode);
158 printf(" size of initialized data 0x%-8lx %lu\n",
159 optionalHeader->SizeOfInitializedData, optionalHeader->SizeOfInitializedData);
160 printf(" size of uninitialized data 0x%-8lx %lu\n",
161 optionalHeader->SizeOfUninitializedData, optionalHeader->SizeOfUninitializedData);
162 printf(" entrypoint RVA 0x%-8lx %lu\n",
163 optionalHeader->AddressOfEntryPoint, optionalHeader->AddressOfEntryPoint);
164 printf(" base of code 0x%-8lx %lu\n",
165 optionalHeader->BaseOfCode, optionalHeader->BaseOfCode);
166 printf(" base of data 0x%-8lX %lu\n",
167 optionalHeader->BaseOfData, optionalHeader->BaseOfData);
168 printf(" image base 0x%-8lX %lu\n",
169 optionalHeader->ImageBase, optionalHeader->ImageBase);
170 printf(" section align 0x%-8lx %lu\n",
171 optionalHeader->SectionAlignment, optionalHeader->SectionAlignment);
172 printf(" file align 0x%-8lx %lu\n",
173 optionalHeader->FileAlignment, optionalHeader->FileAlignment);
174 printf(" required OS version %u.%02u\n",
175 optionalHeader->MajorOperatingSystemVersion, optionalHeader->MinorOperatingSystemVersion);
176 printf(" image version %u.%02u\n",
177 optionalHeader->MajorImageVersion, optionalHeader->MinorImageVersion);
178 printf(" subsystem version %u.%02u\n",
179 optionalHeader->MajorSubsystemVersion, optionalHeader->MinorSubsystemVersion);
180 printf(" Win32 Version 0x%lX\n", optionalHeader->Win32VersionValue);
181 printf(" size of image 0x%-8lx %lu\n",
182 optionalHeader->SizeOfImage, optionalHeader->SizeOfImage);
183 printf(" size of headers 0x%-8lx %lu\n",
184 optionalHeader->SizeOfHeaders, optionalHeader->SizeOfHeaders);
185 printf(" checksum 0x%lX\n", optionalHeader->CheckSum);
186 switch (optionalHeader->Subsystem)
188 default:
189 case IMAGE_SUBSYSTEM_UNKNOWN: str = "Unknown"; break;
190 case IMAGE_SUBSYSTEM_NATIVE: str = "Native"; break;
191 case IMAGE_SUBSYSTEM_WINDOWS_GUI: str = "Windows GUI"; break;
192 case IMAGE_SUBSYSTEM_WINDOWS_CUI: str = "Windows CUI"; break;
193 case IMAGE_SUBSYSTEM_OS2_CUI: str = "OS/2 CUI"; break;
194 case IMAGE_SUBSYSTEM_POSIX_CUI: str = "Posix CUI"; break;
196 printf(" Subsystem 0x%X (%s)\n", optionalHeader->Subsystem, str);
197 printf(" DLL flags 0x%X\n", optionalHeader->DllCharacteristics);
198 printf(" stack reserve size 0x%-8lx %lu\n",
199 optionalHeader->SizeOfStackReserve, optionalHeader->SizeOfStackReserve);
200 printf(" stack commit size 0x%-8lx %lu\n",
201 optionalHeader->SizeOfStackCommit, optionalHeader->SizeOfStackCommit);
202 printf(" heap reserve size 0x%-8lx %lu\n",
203 optionalHeader->SizeOfHeapReserve, optionalHeader->SizeOfHeapReserve);
204 printf(" heap commit size 0x%-8lx %lu\n",
205 optionalHeader->SizeOfHeapCommit, optionalHeader->SizeOfHeapCommit);
206 printf(" loader flags 0x%lX\n", optionalHeader->LoaderFlags);
207 printf(" RVAs & sizes 0x%lX\n", optionalHeader->NumberOfRvaAndSizes);
208 printf("\n");
210 printf("Data Directory\n");
211 printf("%ld\n", optionalHeader->NumberOfRvaAndSizes * sizeof(IMAGE_DATA_DIRECTORY));
213 for (i = 0; i < optionalHeader->NumberOfRvaAndSizes && i < 16; i++)
215 printf(" %-12s rva: 0x%-8lX size: %8lu\n",
216 DirectoryNames[i], optionalHeader->DataDirectory[i].VirtualAddress,
217 optionalHeader->DataDirectory[i].Size);
219 printf("\n");
222 static void dump_sections(void* addr, unsigned num_sect)
224 IMAGE_SECTION_HEADER* sectHead = addr;
225 unsigned i;
227 printf("Section Table\n");
228 for (i = 0; i < num_sect; i++, sectHead++)
230 printf(" %02d %-8.8s VirtSize: %-8lu VirtAddr: %-8lu 0x%08lx\n",
231 i + 1, sectHead->Name, sectHead->Misc.VirtualSize, sectHead->VirtualAddress,
232 sectHead->VirtualAddress);
233 printf(" raw data offs: %-8lu raw data size: %-8lu\n",
234 sectHead->PointerToRawData, sectHead->SizeOfRawData);
235 printf(" relocation offs: %-8lu relocations: %-8u\n",
236 sectHead->PointerToRelocations, sectHead->NumberOfRelocations);
237 printf(" line # offs: %-8lu line #'s: %-8u\n",
238 sectHead->PointerToLinenumbers, sectHead->NumberOfLinenumbers);
239 printf(" characteristics: 0x%08lx\n", sectHead->Characteristics);
240 printf(" ");
241 #define X(b,s) if (sectHead->Characteristics & b) printf(s " ")
242 /* #define IMAGE_SCN_TYPE_REG 0x00000000 - Reserved */
243 /* #define IMAGE_SCN_TYPE_DSECT 0x00000001 - Reserved */
244 /* #define IMAGE_SCN_TYPE_NOLOAD 0x00000002 - Reserved */
245 /* #define IMAGE_SCN_TYPE_GROUP 0x00000004 - Reserved */
246 /* #define IMAGE_SCN_TYPE_NO_PAD 0x00000008 - Reserved */
247 /* #define IMAGE_SCN_TYPE_COPY 0x00000010 - Reserved */
249 X(IMAGE_SCN_CNT_CODE, "CODE");
250 X(IMAGE_SCN_CNT_INITIALIZED_DATA, "INITIALIZED_DATA");
251 X(IMAGE_SCN_CNT_UNINITIALIZED_DATA, "UNINITIALIZED_DATA");
253 X(IMAGE_SCN_LNK_OTHER, "LNK_OTHER");
254 X(IMAGE_SCN_LNK_INFO, "LNK_INFO");
255 /* #define IMAGE_SCN_TYPE_OVER 0x00000400 - Reserved */
256 X(IMAGE_SCN_LNK_REMOVE, "LNK_REMOVE");
257 X(IMAGE_SCN_LNK_COMDAT, "LNK_COMDAT");
259 /* 0x00002000 - Reserved */
260 /* #define IMAGE_SCN_MEM_PROTECTED 0x00004000 - Obsolete */
261 X(IMAGE_SCN_MEM_FARDATA, "MEM_FARDATA");
263 /* #define IMAGE_SCN_MEM_SYSHEAP 0x00010000 - Obsolete */
264 X(IMAGE_SCN_MEM_PURGEABLE, "MEM_PURGEABLE");
265 X(IMAGE_SCN_MEM_16BIT, "MEM_16BIT");
266 X(IMAGE_SCN_MEM_LOCKED, "MEM_LOCKED");
267 X(IMAGE_SCN_MEM_PRELOAD, "MEM_PRELOAD");
269 X(IMAGE_SCN_ALIGN_1BYTES, "ALIGN_1BYTES");
270 X(IMAGE_SCN_ALIGN_2BYTES, "ALIGN_2BYTES");
271 X(IMAGE_SCN_ALIGN_4BYTES, "ALIGN_4BYTES");
272 X(IMAGE_SCN_ALIGN_8BYTES, "ALIGN_8BYTES");
273 X(IMAGE_SCN_ALIGN_16BYTES, "ALIGN_16BYTES");
274 X(IMAGE_SCN_ALIGN_32BYTES, "ALIGN_32BYTES");
275 X(IMAGE_SCN_ALIGN_64BYTES, "ALIGN_64BYTES");
276 /* 0x00800000 - Unused */
278 X(IMAGE_SCN_LNK_NRELOC_OVFL, "LNK_NRELOC_OVFL");
280 X(IMAGE_SCN_MEM_DISCARDABLE, "MEM_DISCARDABLE");
281 X(IMAGE_SCN_MEM_NOT_CACHED, "MEM_NOT_CACHED");
282 X(IMAGE_SCN_MEM_NOT_PAGED, "MEM_NOT_PAGED");
283 X(IMAGE_SCN_MEM_SHARED, "MEM_SHARED");
284 X(IMAGE_SCN_MEM_EXECUTE, "MEM_EXECUTE");
285 X(IMAGE_SCN_MEM_READ, "MEM_READ");
286 X(IMAGE_SCN_MEM_WRITE, "MEM_WRITE");
287 #undef X
288 printf("\n\n");
290 printf("\n");
293 static void dump_dir_exported_functions(void)
295 unsigned int size = 0;
296 IMAGE_EXPORT_DIRECTORY *exportDir = get_dir_and_size(IMAGE_FILE_EXPORT_DIRECTORY, &size);
297 unsigned int i;
298 DWORD* pFunc;
299 DWORD* pName;
300 WORD* pOrdl;
301 DWORD* map;
302 parsed_symbol symbol;
304 if (!exportDir) return;
306 printf("Exports table:\n");
307 printf("\n");
308 printf(" Name: %s\n", (char*)RVA(exportDir->Name, sizeof(DWORD)));
309 printf(" Characteristics: %08lx\n", exportDir->Characteristics);
310 printf(" TimeDateStamp: %08lX %s\n",
311 exportDir->TimeDateStamp, get_time_str(exportDir->TimeDateStamp));
312 printf(" Version: %u.%02u\n", exportDir->MajorVersion, exportDir->MinorVersion);
313 printf(" Ordinal base: %lu\n", exportDir->Base);
314 printf(" # of functions: %lu\n", exportDir->NumberOfFunctions);
315 printf(" # of Names: %lu\n", exportDir->NumberOfNames);
316 printf("Addresses of functions: %08lX\n", exportDir->AddressOfFunctions);
317 printf("Addresses of name ordinals: %08lX\n", exportDir->AddressOfNameOrdinals);
318 printf("Addresses of names: %08lX\n", exportDir->AddressOfNames);
319 printf("\n");
320 printf(" Entry Pt Ordn Name\n");
322 pFunc = RVA(exportDir->AddressOfFunctions, exportDir->NumberOfFunctions * sizeof(DWORD));
323 if (!pFunc) {printf("Can't grab functions' address table\n"); return;}
324 pName = RVA(exportDir->AddressOfNames, exportDir->NumberOfNames * sizeof(DWORD));
325 if (!pName) {printf("Can't grab functions' name table\n"); return;}
326 pOrdl = RVA(exportDir->AddressOfNameOrdinals, exportDir->NumberOfNames * sizeof(WORD));
327 if (!pOrdl) {printf("Can't grab functions' ordinal table\n"); return;}
329 /* bit map of used funcs */
330 map = calloc(((exportDir->NumberOfFunctions + 31) & ~31) / 32, sizeof(DWORD));
331 if (!map) fatal("no memory");
333 for (i = 0; i < exportDir->NumberOfNames; i++, pName++, pOrdl++)
335 char* name;
337 map[*pOrdl / 32] |= 1 << (*pOrdl % 32);
339 name = (char*)RVA(*pName, sizeof(DWORD));
340 if (name && globals.do_demangle)
342 printf(" %08lX %4lu ", pFunc[*pOrdl], exportDir->Base + *pOrdl);
344 symbol_init(&symbol, name);
345 if (symbol_demangle(&symbol) == -1)
346 printf(name);
347 else if (symbol.flags & SYM_DATA)
348 printf(symbol.arg_text[0]);
349 else
350 output_prototype(stdout, &symbol);
351 symbol_clear(&symbol);
353 else
355 printf(" %08lX %4lu %s", pFunc[*pOrdl], exportDir->Base + *pOrdl, name);
357 /* check for forwarded function */
358 if ((char *)RVA(pFunc[*pOrdl],sizeof(void*)) >= (char *)exportDir &&
359 (char *)RVA(pFunc[*pOrdl],sizeof(void*)) < (char *)exportDir + size)
360 printf( " (-> %s)", (char *)RVA(pFunc[*pOrdl],1));
361 printf("\n");
363 pFunc = RVA(exportDir->AddressOfFunctions, exportDir->NumberOfFunctions * sizeof(DWORD));
364 if (!pFunc) {printf("Can't grab functions' address table\n"); return;}
365 for (i = 0; i < exportDir->NumberOfFunctions; i++)
367 if (pFunc[i] && !(map[i / 32] & (1 << (i % 32))))
369 printf(" %08lX %4lu <by ordinal>\n", pFunc[i], exportDir->Base + i);
372 free(map);
373 printf("\n");
376 static void dump_dir_imported_functions(void)
378 IMAGE_IMPORT_DESCRIPTOR *importDesc = get_dir(IMAGE_FILE_IMPORT_DIRECTORY);
379 unsigned nb_imp, i;
381 if (!importDesc) return;
382 nb_imp = PE_nt_headers->OptionalHeader.DataDirectory[IMAGE_FILE_IMPORT_DIRECTORY].Size /
383 sizeof(*importDesc);
384 if (!nb_imp) return;
386 printf("Import Table size: %lu\n",
387 PE_nt_headers->OptionalHeader.DataDirectory[IMAGE_FILE_IMPORT_DIRECTORY].Size);/* FIXME */
389 for (i = 0; i < nb_imp - 1; i++) /* the last descr is set as 0 as a sentinel */
391 IMAGE_THUNK_DATA* il;
392 IMAGE_IMPORT_BY_NAME* iibn;
394 if (!importDesc->Name ||
395 (importDesc->u.OriginalFirstThunk == NULL && importDesc->FirstThunk == NULL))
397 /* FIXME */
398 printf("<<<<<<<null entry\n");
399 break;
401 printf(" offset %lu %s\n", Offset(importDesc), (char*)RVA(importDesc->Name, sizeof(DWORD)));
402 printf(" Hint/Name Table: %08lX\n", (DWORD)importDesc->u.OriginalFirstThunk);
403 printf(" TimeDataStamp: %08lX (%s)\n",
404 importDesc->TimeDateStamp, get_time_str(importDesc->TimeDateStamp));
405 printf(" ForwarderChain: %08lX\n", importDesc->ForwarderChain);
406 printf(" First thunk RVA: %08lX (delta: %u 0x%x)\n",
407 (DWORD)importDesc->FirstThunk, -1, -1); /* FIXME */
409 printf(" Ordn Name\n");
411 il = (importDesc->u.OriginalFirstThunk != 0) ?
412 RVA((DWORD)importDesc->u.OriginalFirstThunk, sizeof(DWORD)) :
413 RVA((DWORD)importDesc->FirstThunk, sizeof(DWORD));
415 if (!il) {printf("Can't grab thunk data, going to next imported DLL\n"); continue;}
417 for (; il->u1.Ordinal; il++)
419 if (IMAGE_SNAP_BY_ORDINAL(il->u1.Ordinal))
421 printf(" %4lu <by ordinal>\n", IMAGE_ORDINAL(il->u1.Ordinal));
423 else
425 iibn = RVA((DWORD)il->u1.AddressOfData, sizeof(DWORD));
426 if (!il)
428 printf("Can't grab import by name info, skipping to next ordinal\n");
430 else
432 printf(" %4u %s %lx\n", iibn->Hint, iibn->Name, (DWORD)il->u1.AddressOfData);
436 printf("\n");
437 importDesc++;
439 printf("\n");
442 static void dump_dir_debug_dir(IMAGE_DEBUG_DIRECTORY* idd, int idx)
444 const char* str;
446 printf("Directory %02u\n", idx + 1);
447 printf(" Characteristics: %08lX\n", idd->Characteristics);
448 printf(" TimeDateStamp: %08lX %s\n",
449 idd->TimeDateStamp, get_time_str(idd->TimeDateStamp));
450 printf(" Version %u.%02u\n", idd->MajorVersion, idd->MinorVersion);
451 switch (idd->Type)
453 default:
454 case IMAGE_DEBUG_TYPE_UNKNOWN: str = "UNKNOWN"; break;
455 case IMAGE_DEBUG_TYPE_COFF: str = "COFF"; break;
456 case IMAGE_DEBUG_TYPE_CODEVIEW: str = "CODEVIEW"; break;
457 case IMAGE_DEBUG_TYPE_FPO: str = "FPO"; break;
458 case IMAGE_DEBUG_TYPE_MISC: str = "MISC"; break;
459 case IMAGE_DEBUG_TYPE_EXCEPTION: str = "EXCEPTION"; break;
460 case IMAGE_DEBUG_TYPE_FIXUP: str = "FIXUP"; break;
461 case IMAGE_DEBUG_TYPE_OMAP_TO_SRC: str = "OMAP_TO_SRC"; break;
462 case IMAGE_DEBUG_TYPE_OMAP_FROM_SRC:str = "OMAP_FROM_SRC"; break;
463 case IMAGE_DEBUG_TYPE_BORLAND: str = "BORLAND"; break;
464 case IMAGE_DEBUG_TYPE_RESERVED10: str = "RESERVED10"; break;
466 printf(" Type: %lu (%s)\n", idd->Type, str);
467 printf(" SizeOfData: %lu\n", idd->SizeOfData);
468 printf(" AddressOfRawData: %08lX\n", idd->AddressOfRawData);
469 printf(" PointerToRawData: %08lX\n", idd->PointerToRawData);
471 switch (idd->Type)
473 case IMAGE_DEBUG_TYPE_UNKNOWN:
474 break;
475 case IMAGE_DEBUG_TYPE_COFF:
476 dump_coff(idd->PointerToRawData, idd->SizeOfData,
477 (char*)PE_nt_headers + sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER) + PE_nt_headers->FileHeader.SizeOfOptionalHeader);
478 break;
479 case IMAGE_DEBUG_TYPE_CODEVIEW:
480 dump_codeview(idd->PointerToRawData, idd->SizeOfData);
481 break;
482 case IMAGE_DEBUG_TYPE_FPO:
483 dump_frame_pointer_omission(idd->PointerToRawData, idd->SizeOfData);
484 break;
485 case IMAGE_DEBUG_TYPE_MISC:
487 IMAGE_DEBUG_MISC* misc = PRD(idd->PointerToRawData, idd->SizeOfData);
488 if (!misc) {printf("Can't get misc debug information\n"); break;}
489 printf(" DataType: %lu (%s)\n",
490 misc->DataType,
491 (misc->DataType == IMAGE_DEBUG_MISC_EXENAME) ? "Exe name" : "Unknown");
492 printf(" Length: %lu\n", misc->Length);
493 printf(" Unicode: %s\n", misc->Unicode ? "Yes" : "No");
494 printf(" Data: %s\n", misc->Data);
496 break;
497 case IMAGE_DEBUG_TYPE_EXCEPTION:
498 break;
499 case IMAGE_DEBUG_TYPE_FIXUP:
500 break;
501 case IMAGE_DEBUG_TYPE_OMAP_TO_SRC:
502 break;
503 case IMAGE_DEBUG_TYPE_OMAP_FROM_SRC:
504 break;
505 case IMAGE_DEBUG_TYPE_BORLAND:
506 break;
507 case IMAGE_DEBUG_TYPE_RESERVED10:
508 break;
510 printf("\n");
513 static void dump_dir_debug(void)
515 IMAGE_DEBUG_DIRECTORY* debugDir = get_dir(IMAGE_FILE_DEBUG_DIRECTORY);
516 unsigned nb_dbg, i;
518 if (!debugDir) return;
519 nb_dbg = PE_nt_headers->OptionalHeader.DataDirectory[IMAGE_FILE_DEBUG_DIRECTORY].Size /
520 sizeof(*debugDir);
521 if (!nb_dbg) return;
523 printf("Debug Table (%u directories)\n", nb_dbg);
525 for (i = 0; i < nb_dbg; i++)
527 dump_dir_debug_dir(debugDir, i);
528 debugDir++;
530 printf("\n");
533 static void dump_dir_tls(void)
535 const IMAGE_TLS_DIRECTORY *dir = get_dir(IMAGE_FILE_THREAD_LOCAL_STORAGE);
536 const DWORD *callbacks;
538 if (!dir) return;
539 printf( "Thread Local Storage\n" );
540 printf( " Raw data %08lx-%08lx (data size %lx zero fill size %lx)\n",
541 dir->StartAddressOfRawData, dir->EndAddressOfRawData,
542 dir->EndAddressOfRawData - dir->StartAddressOfRawData,
543 dir->SizeOfZeroFill );
544 printf( " Index address %08lx\n", (DWORD)dir->AddressOfIndex );
545 printf( " Characteristics %08lx\n", dir->Characteristics );
546 printf( " Callbacks %08lx -> {", (DWORD)dir->AddressOfCallBacks );
547 if (dir->AddressOfCallBacks)
549 DWORD addr = (DWORD)dir->AddressOfCallBacks - PE_nt_headers->OptionalHeader.ImageBase;
550 while ((callbacks = RVA(addr, sizeof(DWORD))) && *callbacks)
552 printf( " %08lx", *callbacks );
553 addr += sizeof(DWORD);
556 printf(" }\n\n");
559 void dump_separate_dbg(void)
561 IMAGE_SEPARATE_DEBUG_HEADER*separateDebugHead = PRD(0, sizeof(separateDebugHead));
562 unsigned nb_dbg;
563 unsigned i;
564 IMAGE_DEBUG_DIRECTORY* debugDir;
566 if (!separateDebugHead) {printf("Can't grab the separate header, aborting\n"); return;}
568 printf ("Signature: %.2s (0x%4X)\n",
569 (char*)&separateDebugHead->Signature, separateDebugHead->Signature);
570 printf ("Flags: 0x%04X\n", separateDebugHead->Flags);
571 printf ("Machine: 0x%04X (%s)\n",
572 separateDebugHead->Machine, get_machine_str(separateDebugHead->Machine));
573 printf ("Characteristics: 0x%04X\n", separateDebugHead->Characteristics);
574 printf ("TimeDateStamp: 0x%08lX (%s)\n",
575 separateDebugHead->TimeDateStamp, get_time_str(separateDebugHead->TimeDateStamp));
576 printf ("CheckSum: 0x%08lX\n", separateDebugHead->CheckSum);
577 printf ("ImageBase: 0x%08lX\n", separateDebugHead->ImageBase);
578 printf ("SizeOfImage: 0x%08lX\n", separateDebugHead->SizeOfImage);
579 printf ("NumberOfSections: 0x%08lX\n", separateDebugHead->NumberOfSections);
580 printf ("ExportedNamesSize: 0x%08lX\n", separateDebugHead->ExportedNamesSize);
581 printf ("DebugDirectorySize: 0x%08lX\n", separateDebugHead->DebugDirectorySize);
583 if (!PRD(sizeof(IMAGE_SEPARATE_DEBUG_HEADER),
584 separateDebugHead->NumberOfSections * sizeof(IMAGE_SECTION_HEADER)))
585 {printf("Can't get the sections, aborting\n"); return;}
587 dump_sections(separateDebugHead + 1, separateDebugHead->NumberOfSections);
589 nb_dbg = separateDebugHead->DebugDirectorySize / sizeof(IMAGE_DEBUG_DIRECTORY);
590 debugDir = PRD(sizeof(IMAGE_SEPARATE_DEBUG_HEADER) +
591 separateDebugHead->NumberOfSections * sizeof(IMAGE_SECTION_HEADER) +
592 separateDebugHead->ExportedNamesSize,
593 nb_dbg * sizeof(IMAGE_DEBUG_DIRECTORY));
594 if (!debugDir) {printf("Couldn't get the debug directory info, aborting\n");return;}
596 printf("Debug Table (%u directories)\n", nb_dbg);
598 for (i = 0; i < nb_dbg; i++)
600 dump_dir_debug_dir(debugDir, i);
601 debugDir++;
605 static const char *get_resource_type( unsigned int id )
607 static const char *types[] =
609 NULL,
610 "CURSOR",
611 "BITMAP",
612 "ICON",
613 "MENU",
614 "DIALOG",
615 "STRING",
616 "FONTDIR",
617 "FONT",
618 "ACCELERATOR",
619 "RCDATA",
620 "MESSAGETABLE",
621 "GROUP_CURSOR",
622 NULL,
623 "GROUP_ICON",
624 NULL,
625 "VERSION",
626 "DLGINCLUDE",
627 NULL,
628 "PLUGPLAY",
629 "VXD",
630 "ANICURSOR",
631 "ANIICON",
632 "HTML"
635 if ((size_t)id < sizeof(types)/sizeof(types[0])) return types[id];
636 return NULL;
639 /* dump an ASCII string with proper escaping */
640 static int dump_strA( const unsigned char *str, size_t len )
642 static const char escapes[32] = ".......abtnvfr.............e....";
643 char buffer[256];
644 char *pos = buffer;
645 int count = 0;
647 for (; len; str++, len--)
649 if (pos > buffer + sizeof(buffer) - 8)
651 fwrite( buffer, pos - buffer, 1, stdout );
652 count += pos - buffer;
653 pos = buffer;
655 if (*str > 127) /* hex escape */
657 pos += sprintf( pos, "\\x%02x", *str );
658 continue;
660 if (*str < 32) /* octal or C escape */
662 if (!*str && len == 1) continue; /* do not output terminating NULL */
663 if (escapes[*str] != '.')
664 pos += sprintf( pos, "\\%c", escapes[*str] );
665 else if (len > 1 && str[1] >= '0' && str[1] <= '7')
666 pos += sprintf( pos, "\\%03o", *str );
667 else
668 pos += sprintf( pos, "\\%o", *str );
669 continue;
671 if (*str == '\\') *pos++ = '\\';
672 *pos++ = *str;
674 fwrite( buffer, pos - buffer, 1, stdout );
675 count += pos - buffer;
676 return count;
679 /* dump a Unicode string with proper escaping */
680 static int dump_strW( const WCHAR *str, size_t len )
682 static const char escapes[32] = ".......abtnvfr.............e....";
683 char buffer[256];
684 char *pos = buffer;
685 int count = 0;
687 for (; len; str++, len--)
689 if (pos > buffer + sizeof(buffer) - 8)
691 fwrite( buffer, pos - buffer, 1, stdout );
692 count += pos - buffer;
693 pos = buffer;
695 if (*str > 127) /* hex escape */
697 if (len > 1 && str[1] < 128 && isxdigit((char)str[1]))
698 pos += sprintf( pos, "\\x%04x", *str );
699 else
700 pos += sprintf( pos, "\\x%x", *str );
701 continue;
703 if (*str < 32) /* octal or C escape */
705 if (!*str && len == 1) continue; /* do not output terminating NULL */
706 if (escapes[*str] != '.')
707 pos += sprintf( pos, "\\%c", escapes[*str] );
708 else if (len > 1 && str[1] >= '0' && str[1] <= '7')
709 pos += sprintf( pos, "\\%03o", *str );
710 else
711 pos += sprintf( pos, "\\%o", *str );
712 continue;
714 if (*str == '\\') *pos++ = '\\';
715 *pos++ = *str;
717 fwrite( buffer, pos - buffer, 1, stdout );
718 count += pos - buffer;
719 return count;
722 /* dump data for a STRING resource */
723 static void dump_string_data( const WCHAR *ptr, unsigned int size, unsigned int id, const char *prefix )
725 int i;
727 for (i = 0; i < 16 && size; i++)
729 unsigned len = *ptr++;
731 if (len >= size)
733 len = size;
734 size = 0;
736 else size -= len + 1;
738 if (len)
740 printf( "%s%04x \"", prefix, (id - 1) * 16 + i );
741 dump_strW( ptr, len );
742 printf( "\"\n" );
743 ptr += len;
748 /* dump data for a MESSAGETABLE resource */
749 static void dump_msgtable_data( const void *ptr, unsigned int size, unsigned int id, const char *prefix )
751 const MESSAGE_RESOURCE_DATA *data = ptr;
752 const MESSAGE_RESOURCE_BLOCK *block = data->Blocks;
753 unsigned i, j;
755 for (i = 0; i < data->NumberOfBlocks; i++, block++)
757 const MESSAGE_RESOURCE_ENTRY *entry;
759 entry = (const MESSAGE_RESOURCE_ENTRY *)((const char *)data + block->OffsetToEntries);
760 for (j = block->LowId; j <= block->HighId; j++)
762 if (entry->Flags & MESSAGE_RESOURCE_UNICODE)
764 const WCHAR *str = (const WCHAR *)entry->Text;
765 printf( "%s%08x L\"", prefix, j );
766 dump_strW( str, strlenW(str) );
767 printf( "\"\n" );
769 else
771 printf( "%s%08x \"", prefix, j );
772 dump_strA( entry->Text, strlen(entry->Text) );
773 printf( "\"\n" );
775 entry = (const MESSAGE_RESOURCE_ENTRY *)((const char *)entry + entry->Length);
780 static void dump_dir_resource(void)
782 const IMAGE_RESOURCE_DIRECTORY *root = get_dir(IMAGE_FILE_RESOURCE_DIRECTORY);
783 const IMAGE_RESOURCE_DIRECTORY *namedir;
784 const IMAGE_RESOURCE_DIRECTORY *langdir;
785 const IMAGE_RESOURCE_DIRECTORY_ENTRY *e1, *e2, *e3;
786 const IMAGE_RESOURCE_DIR_STRING_U *string;
787 const IMAGE_RESOURCE_DATA_ENTRY *data;
788 int i, j, k;
790 if (!root) return;
792 printf( "Resources:" );
794 for (i = 0; i< root->NumberOfNamedEntries + root->NumberOfIdEntries; i++)
796 e1 = (const IMAGE_RESOURCE_DIRECTORY_ENTRY*)(root + 1) + i;
797 namedir = (const IMAGE_RESOURCE_DIRECTORY *)((const char *)root + e1->u2.s3.OffsetToDirectory);
798 for (j = 0; j < namedir->NumberOfNamedEntries + namedir->NumberOfIdEntries; j++)
800 e2 = (const IMAGE_RESOURCE_DIRECTORY_ENTRY*)(namedir + 1) + j;
801 langdir = (const IMAGE_RESOURCE_DIRECTORY *)((const char *)root + e2->u2.s3.OffsetToDirectory);
802 for (k = 0; k < langdir->NumberOfNamedEntries + langdir->NumberOfIdEntries; k++)
804 e3 = (const IMAGE_RESOURCE_DIRECTORY_ENTRY*)(langdir + 1) + k;
806 printf( "\n " );
807 if (e1->u1.s1.NameIsString)
809 string = (const IMAGE_RESOURCE_DIR_STRING_U*)((const char *)root + e1->u1.s1.NameOffset);
810 dump_unicode_str( string->NameString, string->Length );
812 else
814 const char *type = get_resource_type( e1->u1.s2.Id );
815 if (type) printf( "%s", type );
816 else printf( "%04x", e1->u1.s2.Id );
819 printf( " Name=" );
820 if (e2->u1.s1.NameIsString)
822 string = (const IMAGE_RESOURCE_DIR_STRING_U*) ((const char *)root + e2->u1.s1.NameOffset);
823 dump_unicode_str( string->NameString, string->Length );
825 else
826 printf( "%04x", e2->u1.s2.Id );
828 printf( " Language=%04x:\n", e3->u1.s2.Id );
829 data = (const IMAGE_RESOURCE_DATA_ENTRY *)((const char *)root + e3->u2.OffsetToData);
830 if (e1->u1.s1.NameIsString)
832 dump_data( RVA( data->OffsetToData, data->Size ), data->Size, " " );
834 else switch(e1->u1.s2.Id)
836 case 6:
837 dump_string_data( RVA( data->OffsetToData, data->Size ), data->Size,
838 e2->u1.s2.Id, " " );
839 break;
840 case 11:
841 dump_msgtable_data( RVA( data->OffsetToData, data->Size ), data->Size,
842 e2->u1.s2.Id, " " );
843 break;
844 default:
845 dump_data( RVA( data->OffsetToData, data->Size ), data->Size, " " );
846 break;
851 printf( "\n\n" );
854 void pe_dump(void* pmt)
856 int all = (globals.dumpsect != NULL) && strcmp(globals.dumpsect, "ALL") == 0;
858 PE_nt_headers = pmt;
859 if (globals.do_dumpheader)
861 dump_pe_header();
862 /* FIXME: should check ptr */
863 dump_sections((char*)PE_nt_headers + sizeof(DWORD) +
864 sizeof(IMAGE_FILE_HEADER) + PE_nt_headers->FileHeader.SizeOfOptionalHeader,
865 PE_nt_headers->FileHeader.NumberOfSections);
867 else if (!globals.dumpsect)
869 /* show at least something here */
870 dump_pe_header();
873 if (globals.dumpsect)
875 if (all || !strcmp(globals.dumpsect, "import"))
876 dump_dir_imported_functions();
877 if (all || !strcmp(globals.dumpsect, "export"))
878 dump_dir_exported_functions();
879 if (all || !strcmp(globals.dumpsect, "debug"))
880 dump_dir_debug();
881 if (all || !strcmp(globals.dumpsect, "resource"))
882 dump_dir_resource();
883 if (all || !strcmp(globals.dumpsect, "tls"))
884 dump_dir_tls();
885 #if 0
886 /* FIXME: not implemented yet */
887 if (all || !strcmp(globals.dumpsect, "reloc"))
888 dump_dir_reloc();
889 #endif
893 typedef struct _dll_symbol {
894 size_t ordinal;
895 char *symbol;
896 } dll_symbol;
898 static dll_symbol *dll_symbols = NULL;
899 static dll_symbol *dll_current_symbol = NULL;
901 /* Compare symbols by ordinal for qsort */
902 static int symbol_cmp(const void *left, const void *right)
904 return ((const dll_symbol *)left)->ordinal > ((const dll_symbol *)right)->ordinal;
907 /*******************************************************************
908 * dll_close
910 * Free resources used by DLL
912 /* FIXME: Not used yet
913 static void dll_close (void)
915 dll_symbol* ds;
917 if (!dll_symbols) {
918 fatal("No symbols");
920 for (ds = dll_symbols; ds->symbol; ds++)
921 free(ds->symbol);
922 free (dll_symbols);
923 dll_symbols = NULL;
927 static void do_grab_sym( enum FileSig sig, void* pmt )
929 IMAGE_EXPORT_DIRECTORY *exportDir;
930 unsigned i, j;
931 DWORD* pName;
932 DWORD* pFunc;
933 WORD* pOrdl;
934 const char* ptr;
935 DWORD* map;
937 PE_nt_headers = pmt;
938 if (!(exportDir = get_dir(IMAGE_FILE_EXPORT_DIRECTORY))) return;
940 pName = RVA(exportDir->AddressOfNames, exportDir->NumberOfNames * sizeof(DWORD));
941 if (!pName) {printf("Can't grab functions' name table\n"); return;}
942 pOrdl = RVA(exportDir->AddressOfNameOrdinals, exportDir->NumberOfNames * sizeof(WORD));
943 if (!pOrdl) {printf("Can't grab functions' ordinal table\n"); return;}
945 /* dll_close(); */
947 if (!(dll_symbols = (dll_symbol *) malloc((exportDir->NumberOfFunctions + 1) *
948 sizeof (dll_symbol))))
949 fatal ("Out of memory");
950 if (exportDir->AddressOfFunctions != exportDir->NumberOfNames || exportDir->Base > 1)
951 globals.do_ordinals = 1;
953 /* bit map of used funcs */
954 map = calloc(((exportDir->NumberOfFunctions + 31) & ~31) / 32, sizeof(DWORD));
955 if (!map) fatal("no memory");
957 for (j = 0; j < exportDir->NumberOfNames; j++, pOrdl++)
959 map[*pOrdl / 32] |= 1 << (*pOrdl % 32);
960 ptr = RVA(*pName++, sizeof(DWORD));
961 if (!ptr) ptr = "cant_get_function";
962 dll_symbols[j].symbol = strdup(ptr);
963 dll_symbols[j].ordinal = exportDir->Base + *pOrdl;
964 assert(dll_symbols[j].symbol);
966 pFunc = RVA(exportDir->AddressOfFunctions, exportDir->NumberOfFunctions * sizeof(DWORD));
967 if (!pFunc) {printf("Can't grab functions' address table\n"); return;}
969 for (i = 0; i < exportDir->NumberOfFunctions; i++)
971 if (pFunc[i] && !(map[i / 32] & (1 << (i % 32))))
973 char ordinal_text[256];
974 /* Ordinal only entry */
975 snprintf (ordinal_text, sizeof(ordinal_text), "%s_%lu",
976 globals.forward_dll ? globals.forward_dll : OUTPUT_UC_DLL_NAME,
977 exportDir->Base + i);
978 str_toupper(ordinal_text);
979 dll_symbols[j].symbol = strdup(ordinal_text);
980 assert(dll_symbols[j].symbol);
981 dll_symbols[j].ordinal = exportDir->Base + i;
982 j++;
983 assert(j <= exportDir->NumberOfFunctions);
986 free(map);
988 if (NORMAL)
989 printf("%lu named symbols in DLL, %lu total, %d unique (ordinal base = %ld)\n",
990 exportDir->NumberOfNames, exportDir->NumberOfFunctions, j, exportDir->Base);
992 qsort( dll_symbols, j, sizeof(dll_symbol), symbol_cmp );
994 dll_symbols[j].symbol = NULL;
996 dll_current_symbol = dll_symbols;
999 /*******************************************************************
1000 * dll_open
1002 * Open a DLL and read in exported symbols
1004 int dll_open (const char *dll_name)
1006 return dump_analysis(dll_name, do_grab_sym, SIG_PE);
1009 /*******************************************************************
1010 * dll_next_symbol
1012 * Get next exported symbol from dll
1014 int dll_next_symbol (parsed_symbol * sym)
1016 if (!dll_current_symbol->symbol)
1017 return 1;
1019 assert (dll_symbols);
1021 sym->symbol = strdup (dll_current_symbol->symbol);
1022 sym->ordinal = dll_current_symbol->ordinal;
1023 dll_current_symbol++;
1024 return 0;