14 #define PATH_SEPARATOR ';'
16 #define PATH_SEPARATOR ':'
19 /* get pointer to section header n */
20 #define IMAGE_SECTION_HDR(n) ((PIMAGE_SECTION_HEADER) ((char *) nt_hdr32 + \
21 4 + sizeof(IMAGE_FILE_HEADER) + \
22 nt_hdr32->FileHeader.SizeOfOptionalHeader + \
23 n * sizeof(IMAGE_SECTION_HEADER)))
25 /* convert relative virtual address to a useable pointer */
26 #define RVA_TO_PTR(rva,type) ((type) rva_to_ptr((DWORD) rva))
28 typedef struct str_list {
30 struct str_list *next;
33 extern void yyparse(void);
35 static void *xmalloc(size_t count);
36 static void add_path_list(char *path);
37 static const char *find_file(const char *name);
38 static void str_list_add(str_list **head, const char *s);
39 static void parse_headers();
40 static void dump_symbol(char *name, int ord, DWORD rva);
42 static const char mz_sign[2] = {'M','Z'};
43 static const char pe_sign[4] = {'P','E','\0','\0'};
44 static const char exp_sign[6] = {'.','e','d','a','t','a'};
46 static PIMAGE_DOS_HEADER dos_hdr;
47 static PIMAGE_NT_HEADERS32 nt_hdr32;
48 static PIMAGE_NT_HEADERS64 nt_hdr64;
50 static char *filename = NULL;
51 static char *program_name;
52 static char *cpp = "gcc -E -xc-header";
54 str_tree *symbols = NULL;
55 static str_list *inc_path = NULL;
56 static str_list *header_files = NULL;
58 static int verbose = 0;
59 static int ordinal_flag = 0;
64 main(int argc, char *argv[])
66 PIMAGE_SECTION_HEADER section;
67 DWORD exp_rva, exp_size;
69 #if defined(_WIN32) && !defined(_WIN64)
71 /* If running on 64-bit Windows and built as a 32-bit process, try
72 * disable Wow64 file system redirection, so that we can open DLLs
73 * in the real system32 folder if requested.
76 PVOID old_redirection;
80 extern __declspec(dllimport) HMODULE __stdcall GetModuleHandleA(char *name);
81 extern __declspec(dllimport) PVOID __stdcall GetProcAddress(HMODULE module, char *name);
83 BOOL (__stdcall *pWow64DisableWow64FsRedirection) (PVOID *old_value);
85 kernel32 = GetModuleHandleA("kernel32.dll");
86 pWow64DisableWow64FsRedirection = GetProcAddress(kernel32, "Wow64DisableWow64FsRedirection");
88 if (pWow64DisableWow64FsRedirection)
89 pWow64DisableWow64FsRedirection(&old_redirection);
92 program_name = argv[0];
94 /* add standard include paths */
95 add_path_list(getenv("C_INCLUDE_PATH"));
96 add_path_list(getenv("CPLUS_INCLUDE_PATH"));
98 /* since when does PATH have anything to do with headers? */
99 add_path_list(getenv("PATH"));
102 /* parse command line */
103 for ( i = 1; i < argc; i++ )
105 if (argv[i][0] == '-')
118 fprintf(stderr, "-h requires an argument\n");
121 str_list_add(&header_files, argv[i]);
126 fprintf(stderr, "-p requires an argument\n");
132 fprintf(stderr, "%s: Unknown option: %s\n",
133 program_name, argv[i]);
141 if (filename == NULL)
143 printf("PExports %d.%d Copyright 1998, Anders Norlander\n"
144 "Changed 1999, Paul Sokolovsky\n"
145 "Changed 2008, Tor Lillqvist\n"
146 "This program is free software; you may redistribute it under the terms of\n"
147 "the GNU General Public License. This program has absolutely no warranty.\n"
149 "\nUsage: %s [-v] [-o] [-h header] [-p preprocessor] dll\n"
150 " -h\tparse header\n"
151 " -o\tprint ordinals\n"
152 " -p\tset preprocessor program\n"
153 " -v\tverbose mode\n"
154 "\nReport bugs to anorland@hem2.passagen.se,\n"
155 "Paul.Sokolovsky@technologist.com\n"
157 VER_MAJOR, VER_MINOR,
162 /* parse headers and build symbol tree */
166 dos_hdr = load_pe_image(filename);
169 fprintf(stderr, "%s: %s: could not load PE image\n",
170 program_name, filename);
174 nt_hdr32 = (PIMAGE_NT_HEADERS32) ((char *) dos_hdr + dos_hdr->e_lfanew);
175 nt_hdr64 = (PIMAGE_NT_HEADERS64) nt_hdr32;
177 if (nt_hdr32->FileHeader.Machine == IMAGE_FILE_MACHINE_I386) {
178 exp_rva = nt_hdr32->OptionalHeader.DataDirectory[0].VirtualAddress;
179 exp_size = nt_hdr32->OptionalHeader.DataDirectory[0].Size;
181 exp_rva = nt_hdr64->OptionalHeader.DataDirectory[0].VirtualAddress;
182 exp_size = nt_hdr64->OptionalHeader.DataDirectory[0].Size;
187 for (i = 0; i < nt_hdr32->FileHeader.NumberOfSections; i++)
189 section = IMAGE_SECTION_HDR(i);
190 printf("; %-8.8s: RVA: %08x, File offset: %08x\n",
192 section->VirtualAddress,
193 section->PointerToRawData);
197 /* Look for export section */
198 for (i = 0; i < nt_hdr32->FileHeader.NumberOfSections; i++)
200 section = IMAGE_SECTION_HDR(i);
201 if (memcmp(section->Name, exp_sign, sizeof(exp_sign)) == 0)
202 dump_exports(section->VirtualAddress, exp_size);
203 else if ((exp_rva >= section->VirtualAddress) &&
204 (exp_rva < (section->VirtualAddress + section->SizeOfRawData)))
205 dump_exports(exp_rva, exp_size);
212 /* dump exported symbols on stdout */
214 dump_exports(DWORD exports_rva, DWORD exports_size)
216 PIMAGE_SECTION_HEADER section;
217 PIMAGE_EXPORT_DIRECTORY exports;
221 DWORD *function_table;
223 static int first = 1;
225 section = find_section(exports_rva);
228 printf("; Reading exports from section: %s\n",
231 exports = RVA_TO_PTR(exports_rva, PIMAGE_EXPORT_DIRECTORY);
233 /* set up various pointers */
234 export_name = RVA_TO_PTR(exports->Name,char*);
235 ordinal_table = RVA_TO_PTR(exports->AddressOfNameOrdinals,WORD*);
236 name_table = RVA_TO_PTR(exports->AddressOfNames,DWORD*);
237 function_table = RVA_TO_PTR(exports->AddressOfFunctions,void*);
241 printf("; Export table: %s\n", export_name);
242 printf("; Ordinal base: %d\n", exports->Base);
243 printf("; Ordinal table RVA: %08x\n",
244 exports->AddressOfNameOrdinals);
245 printf("; Name table RVA: %07x\n",
246 exports->AddressOfNames);
247 printf("; Export address table RVA: %08x\n",
248 exports->AddressOfFunctions);
253 printf("LIBRARY %s\n", export_name);
258 printf("; LIBRARY %s\n", export_name);
260 for (i = 0; i < exports->NumberOfNames; i++)
262 dump_symbol(RVA_TO_PTR(name_table[i],char*),
263 ordinal_table[i] + exports->Base,
264 function_table[ordinal_table[i]]);
266 int f_off = ordinal_table[i];
268 if(function_table[f_off] >= exports_rva && function_table[f_off] < (exports_rva + exports_size) && verbose) {
269 printf(" ; Forwarder (%s)", RVA_TO_PTR(function_table[f_off], char*));
275 for (i = 0; i < exports->NumberOfFunctions; i++)
277 if ( (function_table[i] >= exports_rva) &&
278 (function_table[i] < (exports_rva + exports_size)))
280 int name_present = 0, n;
282 for(n = 0; n < exports->NumberOfNames; n++) {
283 if(ordinal_table[n] == i) {
290 dump_symbol(strchr(RVA_TO_PTR(function_table[i],char*), '.')+1, i + exports->Base, function_table[i]);
292 printf(" ; WARNING: Symbol name guessed from forwarder (%s)\n", RVA_TO_PTR(function_table[i], char*));
299 dump_symbol(char *name, int ord, DWORD rva)
302 str_tree *symbol = str_tree_find(symbols, name);
303 /* if a symbol was found, emit size of stack */
305 sprintf(s, "%s@%"INT_PTR_FORMAT, name, (INT_PTR) symbol->extra);
307 sprintf(s, "%s", name);
311 printf("%-24s\t@%d", s, ord);
316 PIMAGE_SECTION_HEADER s=find_section(rva);
318 /* Stupid msvc doesn't have .bss section, it spews uninitilized data
321 if (!s) { printf(" DATA"); if (verbose) printf (" ; no section"); }
324 if (!(s->Characteristics&IMAGE_SCN_CNT_CODE)) printf(" DATA");
325 if (verbose) printf (" ; %.8s",s->Name);
330 printf(" ; RVA %08x", rva);
333 /* get section to which rva points */
334 PIMAGE_SECTION_HEADER
335 find_section(DWORD rva)
338 PIMAGE_SECTION_HEADER section = IMAGE_SECTION_HDR(0);
339 for (i = 0; i < nt_hdr32->FileHeader.NumberOfSections; i++, section++)
340 if ((rva >= section->VirtualAddress) &&
341 (rva <= (section->VirtualAddress + section->SizeOfRawData)))
346 /* convert rva to pointer into loaded file */
348 rva_to_ptr(DWORD rva)
350 PIMAGE_SECTION_HEADER section = find_section(rva);
351 if (section->PointerToRawData == 0)
354 return ((char *) dos_hdr + rva - (section->VirtualAddress - section->PointerToRawData));
357 /* Load a portable executable into memory */
359 load_pe_image(const char *filename)
366 PIMAGE_DOS_HEADER phdr;
369 if (stat(filename, &st) == -1)
375 phdr = (PIMAGE_DOS_HEADER) xmalloc(st.st_size);
377 f = fopen(filename, "rb");
386 if (fread(phdr, st.st_size, 1, f) != 1)
392 else if (memcmp(mz_sign, phdr, sizeof(mz_sign)) != 0)
394 fprintf(stderr, "No MZ signature\n");
398 else if (memcmp((char *) phdr + phdr->e_lfanew, pe_sign, sizeof(pe_sign)) != 0)
400 fprintf(stderr, "No PE signature\n");
409 /* parse headers to build symbol tree */
415 #define pclose _pclose
423 header = header_files;
427 /* construct command line */
428 cpp_cmd = strdup(cpp);
431 fprintf(stderr, "%s: out of memory\n", program_name);
434 len = strlen(cpp_cmd);
438 const char *fullname = find_file(header->s);
440 if (fullname == NULL)
445 tmp = strlen(fullname) + 10;
446 cpp_cmd = realloc(cpp_cmd, len + tmp);
449 fprintf(stderr, "%s: out of memory\n", program_name);
453 sprintf(cpp_cmd + len, " %s", fullname);
455 sprintf(cpp_cmd + len, " -include %s", fullname);
457 header = header->next;
462 printf("; %s\n", cpp_cmd);
465 Note: CRTDLL messes up stdout when popen is called so
466 if you try to pipe output through another program
467 with | it will hang. Redirect it to a file instead
468 and pass that file to the program (more,less or whatever).
469 This does not apply to cygwin.
471 f = popen(cpp_cmd, "r");
475 fprintf(stderr, "%s: %s: could not execute\n", program_name, cpp_cmd);
483 /* allocate memory; abort on failure */
485 *xmalloc(size_t count)
487 void *p = malloc(count);
490 fprintf(stderr, "%s: out of memory\n", program_name);
496 /* add string to end of list */
498 str_list_add(str_list **head, const char *s)
500 str_list *node = xmalloc(sizeof(str_list));
516 /* find a file in include path */
518 find_file(const char *name)
520 static char fullname[PATH_MAX];
521 FILE *f = fopen(name, "r");
522 str_list *path = inc_path;
530 strcpy(fullname, path->s);
531 strcat(fullname, "/");
532 strcat(fullname, name);
533 f = fopen(fullname, "r");
545 /* add a environment-style path list to list of include paths */
547 add_path_list(char *path)
554 if (*p == PATH_SEPARATOR)
557 str_list_add(&inc_path, path);
563 if (p[-1] != PATH_SEPARATOR)
564 str_list_add(&inc_path, path);