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;
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;
180 exp_rva = nt_hdr64->OptionalHeader.DataDirectory[0].VirtualAddress;
184 for (i = 0; i < nt_hdr32->FileHeader.NumberOfSections; i++)
186 section = IMAGE_SECTION_HDR(i);
187 printf("; %-8.8s: RVA: %08x, File offset: %08x\n",
189 section->VirtualAddress,
190 section->PointerToRawData);
194 /* Look for export section */
195 for (i = 0; i < nt_hdr32->FileHeader.NumberOfSections; i++)
197 section = IMAGE_SECTION_HDR(i);
198 if (memcmp(section->Name, exp_sign, sizeof(exp_sign)) == 0)
199 dump_exports(section->VirtualAddress);
200 else if ((exp_rva >= section->VirtualAddress) &&
201 (exp_rva < (section->VirtualAddress + section->SizeOfRawData)))
202 dump_exports(exp_rva);
209 /* dump exported symbols on stdout */
211 dump_exports(DWORD exports_rva)
213 PIMAGE_SECTION_HEADER section;
214 PIMAGE_EXPORT_DIRECTORY exports;
218 DWORD *function_table;
220 static int first = 1;
222 section = find_section(exports_rva);
225 printf("; Reading exports from section: %s\n",
228 exports = RVA_TO_PTR(exports_rva, PIMAGE_EXPORT_DIRECTORY);
230 /* set up various pointers */
231 export_name = RVA_TO_PTR(exports->Name,char*);
232 ordinal_table = RVA_TO_PTR(exports->AddressOfNameOrdinals,WORD*);
233 name_table = RVA_TO_PTR(exports->AddressOfNames,DWORD*);
234 function_table = RVA_TO_PTR(exports->AddressOfFunctions,void*);
238 printf("; Export table: %s\n", export_name);
239 printf("; Ordinal base: %d\n", exports->Base);
240 printf("; Ordinal table RVA: %08x\n",
241 exports->AddressOfNameOrdinals);
242 printf("; Name table RVA: %07x\n",
243 exports->AddressOfNames);
244 printf("; Export address table RVA: %08x\n",
245 exports->AddressOfFunctions);
250 printf("LIBRARY %s\n", export_name);
255 printf("; LIBRARY %s\n", export_name);
257 for (i = 0; i < exports->NumberOfNames; i++)
259 dump_symbol(RVA_TO_PTR(name_table[i],char*),
260 ordinal_table[i] + exports->Base,
261 function_table[ordinal_table[i]]);
265 for (i = 0; i < exports->NumberOfFunctions; i++)
267 if ( (function_table[i] >= exports_rva) &&
268 (function_table[i] <= (section->VirtualAddress + section->SizeOfRawData)))
270 dump_symbol(strchr(RVA_TO_PTR(function_table[i],char*), '.')+1,
274 printf(" ; Forwarder\n");
282 dump_symbol(char *name, int ord, DWORD rva)
285 str_tree *symbol = str_tree_find(symbols, name);
286 /* if a symbol was found, emit size of stack */
288 sprintf(s, "%s@%"INT_PTR_FORMAT, name, (INT_PTR) symbol->extra);
290 sprintf(s, "%s", name);
294 printf("%-24s\t@%d", s, ord);
299 PIMAGE_SECTION_HEADER s=find_section(rva);
301 /* Stupid msvc doesn't have .bss section, it spews uninitilized data
304 if (!s) { printf(" DATA"); if (verbose) printf (" ; no section"); }
307 if (!(s->Characteristics&IMAGE_SCN_CNT_CODE)) printf(" DATA");
308 if (verbose) printf (" ; %.8s",s->Name);
313 printf(" ; RVA %08x", rva);
316 /* get section to which rva points */
317 PIMAGE_SECTION_HEADER
318 find_section(DWORD rva)
321 PIMAGE_SECTION_HEADER section = IMAGE_SECTION_HDR(0);
322 for (i = 0; i < nt_hdr32->FileHeader.NumberOfSections; i++, section++)
323 if ((rva >= section->VirtualAddress) &&
324 (rva <= (section->VirtualAddress + section->SizeOfRawData)))
329 /* convert rva to pointer into loaded file */
331 rva_to_ptr(DWORD rva)
333 PIMAGE_SECTION_HEADER section = find_section(rva);
334 if (section->PointerToRawData == 0)
337 return ((char *) dos_hdr + rva - (section->VirtualAddress - section->PointerToRawData));
340 /* Load a portable executable into memory */
342 load_pe_image(const char *filename)
349 PIMAGE_DOS_HEADER phdr;
352 if (stat(filename, &st) == -1)
358 phdr = (PIMAGE_DOS_HEADER) xmalloc(st.st_size);
360 f = fopen(filename, "rb");
369 if (fread(phdr, st.st_size, 1, f) != 1)
375 else if (memcmp(mz_sign, phdr, sizeof(mz_sign)) != 0)
377 fprintf(stderr, "No MZ signature\n");
381 else if (memcmp((char *) phdr + phdr->e_lfanew, pe_sign, sizeof(pe_sign)) != 0)
383 fprintf(stderr, "No PE signature\n");
392 /* parse headers to build symbol tree */
398 #define pclose _pclose
406 header = header_files;
410 /* construct command line */
411 cpp_cmd = strdup(cpp);
414 fprintf(stderr, "%s: out of memory\n", program_name);
417 len = strlen(cpp_cmd);
421 const char *fullname = find_file(header->s);
423 if (fullname == NULL)
428 tmp = strlen(fullname) + 10;
429 cpp_cmd = realloc(cpp_cmd, len + tmp);
432 fprintf(stderr, "%s: out of memory\n", program_name);
436 sprintf(cpp_cmd + len, " %s", fullname);
438 sprintf(cpp_cmd + len, " -include %s", fullname);
440 header = header->next;
445 printf("; %s\n", cpp_cmd);
448 Note: CRTDLL messes up stdout when popen is called so
449 if you try to pipe output through another program
450 with | it will hang. Redirect it to a file instead
451 and pass that file to the program (more,less or whatever).
452 This does not apply to cygwin.
454 f = popen(cpp_cmd, "r");
458 fprintf(stderr, "%s: %s: could not execute\n", program_name, cpp_cmd);
466 /* allocate memory; abort on failure */
468 *xmalloc(size_t count)
470 void *p = malloc(count);
473 fprintf(stderr, "%s: out of memory\n", program_name);
479 /* add string to end of list */
481 str_list_add(str_list **head, const char *s)
483 str_list *node = xmalloc(sizeof(str_list));
499 /* find a file in include path */
501 find_file(const char *name)
503 static char fullname[PATH_MAX];
504 FILE *f = fopen(name, "r");
505 str_list *path = inc_path;
513 strcpy(fullname, path->s);
514 strcat(fullname, "/");
515 strcat(fullname, name);
516 f = fopen(fullname, "r");
528 /* add a environment-style path list to list of include paths */
530 add_path_list(char *path)
537 if (*p == PATH_SEPARATOR)
540 str_list_add(&inc_path, path);
546 if (p[-1] != PATH_SEPARATOR)
547 str_list_add(&inc_path, path);