15 #define PATH_SEPARATOR ';'
17 #define PATH_SEPARATOR ':'
20 /* get pointer to section header n */
21 #define IMAGE_SECTION_HDR(n) \
22 ((IMAGE_SECTION_HEADER *)((char *) nt_hdr32 \
23 + 4 + sizeof(IMAGE_FILE_HEADER) + nt_hdr32->FileHeader.SizeOfOptionalHeader \
24 + n * sizeof(IMAGE_SECTION_HEADER)) \
27 /* convert relative virtual address to a useable pointer */
28 #define RVA_TO_PTR(rva,type) ((type)(rva_to_ptr((uint32_t)(rva))))
30 typedef struct str_list {
32 struct str_list *next;
35 extern void yyparse(void);
37 static void *xmalloc(size_t count);
38 static void add_path_list(char *path);
39 static const char *find_file(const char *name);
40 static void str_list_add(str_list **head, const char *s);
41 static void parse_headers();
42 static void dump_symbol(char *name, int ord, uint32_t rva);
44 static const char mz_sign[2] = {'M','Z'};
45 static const char pe_sign[4] = {'P','E','\0','\0'};
46 static const char exp_sign[6] = {'.','e','d','a','t','a'};
48 static IMAGE_DOS_HEADER *dos_hdr;
49 static IMAGE_NT_HEADERS32 *nt_hdr32;
50 static IMAGE_NT_HEADERS64 *nt_hdr64;
52 static char *filename = NULL;
53 static char *program_name;
54 static char *cpp = "gcc -E -xc-header";
56 str_tree *symbols = NULL;
57 static str_list *inc_path = NULL;
58 static str_list *header_files = NULL;
60 static int verbose = 0;
61 static int ordinal_flag = 0;
66 main(int argc, char *argv[])
68 IMAGE_SECTION_HEADER *section;
69 uint32_t exp_rva, exp_size;
72 # if defined(_WIN32) && !defined(_WIN64)
74 * If running on 64-bit Windows and built as a 32-bit process, try
75 * disable Wow64 file system redirection, so that we can open DLLs
76 * in the real system32 folder if requested.
78 void *old_redirection;
81 extern __declspec(dllimport) void __stdcall *GetModuleHandleA(char *name);
82 extern __declspec(dllimport) void __stdcall *GetProcAddress(void *module, char *name);
84 int32_t (__stdcall *pWow64DisableWow64FsRedirection) (void **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 if( (dos_hdr = load_pe_image(filename)) == NULL )
166 fprintf(stderr, "%s: %s: could not load PE image\n",
167 program_name, filename);
171 nt_hdr32 = (IMAGE_NT_HEADERS32 *) ((char *) dos_hdr + dos_hdr->e_lfanew);
172 nt_hdr64 = (IMAGE_NT_HEADERS64 *) nt_hdr32;
174 if (nt_hdr32->FileHeader.Machine == IMAGE_FILE_MACHINE_I386) {
175 exp_rva = nt_hdr32->OptionalHeader.DataDirectory[0].VirtualAddress;
176 exp_size = nt_hdr32->OptionalHeader.DataDirectory[0].Size;
178 exp_rva = nt_hdr64->OptionalHeader.DataDirectory[0].VirtualAddress;
179 exp_size = nt_hdr64->OptionalHeader.DataDirectory[0].Size;
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, exp_size);
200 else if ((exp_rva >= section->VirtualAddress) &&
201 (exp_rva < (section->VirtualAddress + section->SizeOfRawData)))
202 dump_exports(exp_rva, exp_size);
209 /* dump exported symbols on stdout */
211 dump_exports(uint32_t exports_rva, uint32_t exports_size)
213 IMAGE_SECTION_HEADER *section;
214 IMAGE_EXPORT_DIRECTORY *exports;
216 uint16_t *ordinal_table;
217 uint32_t *name_table;
218 uint32_t *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, IMAGE_EXPORT_DIRECTORY *);
230 /* set up various pointers */
231 export_name = RVA_TO_PTR(exports->Name,char*);
232 ordinal_table = RVA_TO_PTR(exports->AddressOfNameOrdinals, uint16_t *);
233 name_table = RVA_TO_PTR(exports->AddressOfNames, uint32_t *);
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]]);
263 int f_off = ordinal_table[i];
265 if(function_table[f_off] >= exports_rva && function_table[f_off] < (exports_rva + exports_size) && verbose) {
266 printf(" ; Forwarder (%s)", RVA_TO_PTR(function_table[f_off], char*));
272 for (i = 0; i < exports->NumberOfFunctions; i++)
274 if ( (function_table[i] >= exports_rva) &&
275 (function_table[i] < (exports_rva + exports_size)))
277 int name_present = 0, n;
279 for(n = 0; n < exports->NumberOfNames; n++) {
280 if(ordinal_table[n] == i) {
287 dump_symbol(strchr(RVA_TO_PTR(function_table[i],char*), '.')+1, i + exports->Base, function_table[i]);
289 printf(" ; WARNING: Symbol name guessed from forwarder (%s)\n", RVA_TO_PTR(function_table[i], char*));
296 dump_symbol(char *name, int ord, uint32_t rva)
299 str_tree *symbol = str_tree_find(symbols, name);
300 /* if a symbol was found, emit size of stack */
302 sprintf(s, "%s@%"PRIdPTR, name, (intptr_t)(symbol->extra));
304 sprintf(s, "%s", name);
308 printf("%-24s\t@%d", s, ord);
313 IMAGE_SECTION_HEADER *s = find_section(rva);
315 /* Stupid msvc doesn't have .bss section, it spews uninitilized data
318 if (!s) { printf(" DATA"); if (verbose) printf (" ; no section"); }
321 if (!(s->Characteristics&IMAGE_SCN_CNT_CODE)) printf(" DATA");
322 if (verbose) printf (" ; %.8s",s->Name);
327 printf(" ; RVA %08x", rva);
330 /* get section to which rva points */
331 IMAGE_SECTION_HEADER *find_section(uint32_t rva)
334 IMAGE_SECTION_HEADER *section = IMAGE_SECTION_HDR(0);
335 for (i = 0; i < nt_hdr32->FileHeader.NumberOfSections; i++, section++)
336 if ((rva >= section->VirtualAddress) &&
337 (rva <= (section->VirtualAddress + section->SizeOfRawData)))
342 /* convert rva to pointer into loaded file */
344 rva_to_ptr(uint32_t rva)
346 IMAGE_SECTION_HEADER *section = find_section(rva);
347 if (section->PointerToRawData == 0)
350 return ((char *) dos_hdr + rva - (section->VirtualAddress - section->PointerToRawData));
353 /* Load a portable executable into memory */
354 IMAGE_DOS_HEADER *load_pe_image(const char *filename)
361 IMAGE_DOS_HEADER *phdr;
364 if (stat(filename, &st) == -1)
370 phdr = (IMAGE_DOS_HEADER *) xmalloc(st.st_size);
372 f = fopen(filename, "rb");
381 if (fread(phdr, st.st_size, 1, f) != 1)
387 else if (memcmp(mz_sign, phdr, sizeof(mz_sign)) != 0)
389 fprintf(stderr, "No MZ signature\n");
393 else if (memcmp((char *) phdr + phdr->e_lfanew, pe_sign, sizeof(pe_sign)) != 0)
395 fprintf(stderr, "No PE signature\n");
404 /* parse headers to build symbol tree */
410 #define pclose _pclose
418 header = header_files;
422 /* construct command line */
423 cpp_cmd = strdup(cpp);
426 fprintf(stderr, "%s: out of memory\n", program_name);
429 len = strlen(cpp_cmd);
433 const char *fullname = find_file(header->s);
435 if (fullname == NULL)
440 tmp = strlen(fullname) + 10;
441 cpp_cmd = realloc(cpp_cmd, len + tmp);
444 fprintf(stderr, "%s: out of memory\n", program_name);
448 sprintf(cpp_cmd + len, " %s", fullname);
450 sprintf(cpp_cmd + len, " -include %s", fullname);
452 header = header->next;
457 printf("; %s\n", cpp_cmd);
460 Note: CRTDLL messes up stdout when popen is called so
461 if you try to pipe output through another program
462 with | it will hang. Redirect it to a file instead
463 and pass that file to the program (more,less or whatever).
464 This does not apply to cygwin.
466 f = popen(cpp_cmd, "r");
470 fprintf(stderr, "%s: %s: could not execute\n", program_name, cpp_cmd);
478 /* allocate memory; abort on failure */
479 static void *xmalloc(size_t count)
481 void *p = malloc(count);
484 fprintf(stderr, "%s: out of memory\n", program_name);
490 /* add string to end of list */
492 str_list_add(str_list **head, const char *s)
494 str_list *node = xmalloc(sizeof(str_list));
510 /* find a file in include path */
512 find_file(const char *name)
514 static char fullname[PATH_MAX];
515 FILE *f = fopen(name, "r");
516 str_list *path = inc_path;
524 strcpy(fullname, path->s);
525 strcat(fullname, "/");
526 strcat(fullname, name);
527 f = fopen(fullname, "r");
539 /* add a environment-style path list to list of include paths */
541 add_path_list(char *path)
548 if (*p == PATH_SEPARATOR)
551 str_list_add(&inc_path, path);
557 if (p[-1] != PATH_SEPARATOR)
558 str_list_add(&inc_path, path);