15 #define PATH_SEPARATOR ';'
17 #define PATH_SEPARATOR ':'
20 /* get pointer to section header n */
21 #define IMAGE_SECTION_HDR(n) ((PIMAGE_SECTION_HEADER) ((char *) nt_hdr32 + \
22 4 + sizeof(IMAGE_FILE_HEADER) + \
23 nt_hdr32->FileHeader.SizeOfOptionalHeader + \
24 n * sizeof(IMAGE_SECTION_HEADER)))
26 /* convert relative virtual address to a useable pointer */
27 #define RVA_TO_PTR(rva,type) ((type) rva_to_ptr((DWORD) rva))
29 typedef struct str_list {
31 struct str_list *next;
34 extern void yyparse(void);
36 static void *xmalloc(size_t count);
37 static void add_path_list(char *path);
38 static const char *find_file(const char *name);
39 static void str_list_add(str_list **head, const char *s);
40 static void parse_headers();
41 static void dump_symbol(char *name, int ord, DWORD rva);
43 static const char mz_sign[2] = {'M','Z'};
44 static const char pe_sign[4] = {'P','E','\0','\0'};
45 static const char exp_sign[6] = {'.','e','d','a','t','a'};
47 static PIMAGE_DOS_HEADER dos_hdr;
48 static PIMAGE_NT_HEADERS32 nt_hdr32;
49 static PIMAGE_NT_HEADERS64 nt_hdr64;
51 static char *filename = NULL;
52 static char *program_name;
53 static char *cpp = "gcc -E -xc-header";
55 str_tree *symbols = NULL;
56 static str_list *inc_path = NULL;
57 static str_list *header_files = NULL;
59 static int verbose = 0;
60 static int ordinal_flag = 0;
65 main(int argc, char *argv[])
67 PIMAGE_SECTION_HEADER section;
68 DWORD exp_rva, exp_size;
70 #if defined(_WIN32) && !defined(_WIN64)
72 /* If running on 64-bit Windows and built as a 32-bit process, try
73 * disable Wow64 file system redirection, so that we can open DLLs
74 * in the real system32 folder if requested.
77 PVOID old_redirection;
81 extern __declspec(dllimport) HMODULE __stdcall GetModuleHandleA(char *name);
82 extern __declspec(dllimport) PVOID __stdcall GetProcAddress(HMODULE module, char *name);
84 BOOL (__stdcall *pWow64DisableWow64FsRedirection) (PVOID *old_value);
86 kernel32 = GetModuleHandleA("kernel32.dll");
87 pWow64DisableWow64FsRedirection = GetProcAddress(kernel32, "Wow64DisableWow64FsRedirection");
89 if (pWow64DisableWow64FsRedirection)
90 pWow64DisableWow64FsRedirection(&old_redirection);
93 program_name = argv[0];
95 /* add standard include paths */
96 add_path_list(getenv("C_INCLUDE_PATH"));
97 add_path_list(getenv("CPLUS_INCLUDE_PATH"));
99 /* since when does PATH have anything to do with headers? */
100 add_path_list(getenv("PATH"));
103 /* parse command line */
104 for ( i = 1; i < argc; i++ )
106 if (argv[i][0] == '-')
119 fprintf(stderr, "-h requires an argument\n");
122 str_list_add(&header_files, argv[i]);
127 fprintf(stderr, "-p requires an argument\n");
133 fprintf(stderr, "%s: Unknown option: %s\n",
134 program_name, argv[i]);
142 if (filename == NULL)
144 printf("PExports %s; Originally written 1998, Anders Norlander\n"
145 "Updated 1999, Paul Sokolovsky, 2008, Tor Lillqvist, 2013, Keith Marshall\n"
146 "Copyright (C) 1998, 1999, 2008, 2013, MinGW.org Project\n\n"
147 "This program is free software; you may redistribute it under the terms of\n"
148 "the GNU General Public License. This program has absolutely no warranty.\n"
150 "\nUsage: %s [-v] [-o] [-h header] [-p preprocessor] dll\n"
151 " -h\tparse header\n"
152 " -o\tprint ordinals\n"
153 " -p\tset preprocessor program\n"
154 " -v\tverbose mode\n"
155 "\nReport bugs as directed at %s\n",
156 PACKAGE_VERSION_STRING, program_name, PACKAGE_BUG_REPORT);
160 /* parse headers and build symbol tree */
164 dos_hdr = load_pe_image(filename);
167 fprintf(stderr, "%s: %s: could not load PE image\n",
168 program_name, filename);
172 nt_hdr32 = (PIMAGE_NT_HEADERS32) ((char *) dos_hdr + dos_hdr->e_lfanew);
173 nt_hdr64 = (PIMAGE_NT_HEADERS64) nt_hdr32;
175 if (nt_hdr32->FileHeader.Machine == IMAGE_FILE_MACHINE_I386) {
176 exp_rva = nt_hdr32->OptionalHeader.DataDirectory[0].VirtualAddress;
177 exp_size = nt_hdr32->OptionalHeader.DataDirectory[0].Size;
179 exp_rva = nt_hdr64->OptionalHeader.DataDirectory[0].VirtualAddress;
180 exp_size = nt_hdr64->OptionalHeader.DataDirectory[0].Size;
185 for (i = 0; i < nt_hdr32->FileHeader.NumberOfSections; i++)
187 section = IMAGE_SECTION_HDR(i);
188 printf("; %-8.8s: RVA: %08x, File offset: %08x\n",
190 section->VirtualAddress,
191 section->PointerToRawData);
195 /* Look for export section */
196 for (i = 0; i < nt_hdr32->FileHeader.NumberOfSections; i++)
198 section = IMAGE_SECTION_HDR(i);
199 if (memcmp(section->Name, exp_sign, sizeof(exp_sign)) == 0)
200 dump_exports(section->VirtualAddress, exp_size);
201 else if ((exp_rva >= section->VirtualAddress) &&
202 (exp_rva < (section->VirtualAddress + section->SizeOfRawData)))
203 dump_exports(exp_rva, exp_size);
210 /* dump exported symbols on stdout */
212 dump_exports(DWORD exports_rva, DWORD exports_size)
214 PIMAGE_SECTION_HEADER section;
215 PIMAGE_EXPORT_DIRECTORY exports;
219 DWORD *function_table;
221 static int first = 1;
223 section = find_section(exports_rva);
226 printf("; Reading exports from section: %s\n",
229 exports = RVA_TO_PTR(exports_rva, PIMAGE_EXPORT_DIRECTORY);
231 /* set up various pointers */
232 export_name = RVA_TO_PTR(exports->Name,char*);
233 ordinal_table = RVA_TO_PTR(exports->AddressOfNameOrdinals,WORD*);
234 name_table = RVA_TO_PTR(exports->AddressOfNames,DWORD*);
235 function_table = RVA_TO_PTR(exports->AddressOfFunctions,void*);
239 printf("; Export table: %s\n", export_name);
240 printf("; Ordinal base: %d\n", exports->Base);
241 printf("; Ordinal table RVA: %08x\n",
242 exports->AddressOfNameOrdinals);
243 printf("; Name table RVA: %07x\n",
244 exports->AddressOfNames);
245 printf("; Export address table RVA: %08x\n",
246 exports->AddressOfFunctions);
251 printf("LIBRARY %s\n", export_name);
256 printf("; LIBRARY %s\n", export_name);
258 for (i = 0; i < exports->NumberOfNames; i++)
260 dump_symbol(RVA_TO_PTR(name_table[i],char*),
261 ordinal_table[i] + exports->Base,
262 function_table[ordinal_table[i]]);
264 int f_off = ordinal_table[i];
266 if(function_table[f_off] >= exports_rva && function_table[f_off] < (exports_rva + exports_size) && verbose) {
267 printf(" ; Forwarder (%s)", RVA_TO_PTR(function_table[f_off], char*));
273 for (i = 0; i < exports->NumberOfFunctions; i++)
275 if ( (function_table[i] >= exports_rva) &&
276 (function_table[i] < (exports_rva + exports_size)))
278 int name_present = 0, n;
280 for(n = 0; n < exports->NumberOfNames; n++) {
281 if(ordinal_table[n] == i) {
288 dump_symbol(strchr(RVA_TO_PTR(function_table[i],char*), '.')+1, i + exports->Base, function_table[i]);
290 printf(" ; WARNING: Symbol name guessed from forwarder (%s)\n", RVA_TO_PTR(function_table[i], char*));
297 dump_symbol(char *name, int ord, DWORD rva)
300 str_tree *symbol = str_tree_find(symbols, name);
301 /* if a symbol was found, emit size of stack */
303 sprintf(s, "%s@%"PRIdPTR, name, (intptr_t)(symbol->extra));
305 sprintf(s, "%s", name);
309 printf("%-24s\t@%d", s, ord);
314 PIMAGE_SECTION_HEADER s=find_section(rva);
316 /* Stupid msvc doesn't have .bss section, it spews uninitilized data
319 if (!s) { printf(" DATA"); if (verbose) printf (" ; no section"); }
322 if (!(s->Characteristics&IMAGE_SCN_CNT_CODE)) printf(" DATA");
323 if (verbose) printf (" ; %.8s",s->Name);
328 printf(" ; RVA %08x", rva);
331 /* get section to which rva points */
332 PIMAGE_SECTION_HEADER
333 find_section(DWORD rva)
336 PIMAGE_SECTION_HEADER section = IMAGE_SECTION_HDR(0);
337 for (i = 0; i < nt_hdr32->FileHeader.NumberOfSections; i++, section++)
338 if ((rva >= section->VirtualAddress) &&
339 (rva <= (section->VirtualAddress + section->SizeOfRawData)))
344 /* convert rva to pointer into loaded file */
346 rva_to_ptr(DWORD rva)
348 PIMAGE_SECTION_HEADER section = find_section(rva);
349 if (section->PointerToRawData == 0)
352 return ((char *) dos_hdr + rva - (section->VirtualAddress - section->PointerToRawData));
355 /* Load a portable executable into memory */
357 load_pe_image(const char *filename)
364 PIMAGE_DOS_HEADER phdr;
367 if (stat(filename, &st) == -1)
373 phdr = (PIMAGE_DOS_HEADER) xmalloc(st.st_size);
375 f = fopen(filename, "rb");
384 if (fread(phdr, st.st_size, 1, f) != 1)
390 else if (memcmp(mz_sign, phdr, sizeof(mz_sign)) != 0)
392 fprintf(stderr, "No MZ signature\n");
396 else if (memcmp((char *) phdr + phdr->e_lfanew, pe_sign, sizeof(pe_sign)) != 0)
398 fprintf(stderr, "No PE signature\n");
407 /* parse headers to build symbol tree */
413 #define pclose _pclose
421 header = header_files;
425 /* construct command line */
426 cpp_cmd = strdup(cpp);
429 fprintf(stderr, "%s: out of memory\n", program_name);
432 len = strlen(cpp_cmd);
436 const char *fullname = find_file(header->s);
438 if (fullname == NULL)
443 tmp = strlen(fullname) + 10;
444 cpp_cmd = realloc(cpp_cmd, len + tmp);
447 fprintf(stderr, "%s: out of memory\n", program_name);
451 sprintf(cpp_cmd + len, " %s", fullname);
453 sprintf(cpp_cmd + len, " -include %s", fullname);
455 header = header->next;
460 printf("; %s\n", cpp_cmd);
463 Note: CRTDLL messes up stdout when popen is called so
464 if you try to pipe output through another program
465 with | it will hang. Redirect it to a file instead
466 and pass that file to the program (more,less or whatever).
467 This does not apply to cygwin.
469 f = popen(cpp_cmd, "r");
473 fprintf(stderr, "%s: %s: could not execute\n", program_name, cpp_cmd);
481 /* allocate memory; abort on failure */
483 *xmalloc(size_t count)
485 void *p = malloc(count);
488 fprintf(stderr, "%s: out of memory\n", program_name);
494 /* add string to end of list */
496 str_list_add(str_list **head, const char *s)
498 str_list *node = xmalloc(sizeof(str_list));
514 /* find a file in include path */
516 find_file(const char *name)
518 static char fullname[PATH_MAX];
519 FILE *f = fopen(name, "r");
520 str_list *path = inc_path;
528 strcpy(fullname, path->s);
529 strcat(fullname, "/");
530 strcat(fullname, name);
531 f = fopen(fullname, "r");
543 /* add a environment-style path list to list of include paths */
545 add_path_list(char *path)
552 if (*p == PATH_SEPARATOR)
555 str_list_add(&inc_path, path);
561 if (p[-1] != PATH_SEPARATOR)
562 str_list_add(&inc_path, path);