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)
145 "PExports %s; Originally written 1998, Anders Norlander\n"
146 "Updated 1999, Paul Sokolovsky, 2008, Tor Lillqvist, 2013, 2015, Keith Marshall\n"
147 "Copyright (C) 1998, 1999, 2008, 2013, 2015, MinGW.org Project\n\n"
148 "This program is free software; you may redistribute it under the terms of\n"
149 "the GNU General Public License. This program has absolutely no warranty.\n"
151 "\nUsage: %s [-v] [-o] [-h header] [-p preprocessor] dll\n"
152 " -h\tparse header\n"
153 " -o\tprint ordinals\n"
154 " -p\tset preprocessor program\n"
155 " -v\tverbose mode\n"
156 "\nReport bugs as directed at %s\n",
157 PACKAGE_VERSION_STRING, program_name, PACKAGE_BUG_REPORT);
161 /* parse headers and build symbol tree */
165 if( (dos_hdr = load_pe_image(filename)) == NULL )
167 fprintf(stderr, "%s: %s: could not load PE image\n",
168 program_name, filename);
172 nt_hdr32 = (IMAGE_NT_HEADERS32 *) ((char *) dos_hdr + dos_hdr->e_lfanew);
173 nt_hdr64 = (IMAGE_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(uint32_t exports_rva, uint32_t exports_size)
214 IMAGE_SECTION_HEADER *section;
215 IMAGE_EXPORT_DIRECTORY *exports;
217 uint16_t *ordinal_table;
218 uint32_t *name_table;
219 uint32_t *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, IMAGE_EXPORT_DIRECTORY *);
231 /* set up various pointers */
232 export_name = RVA_TO_PTR(exports->Name, char *);
233 name_table = RVA_TO_PTR(exports->AddressOfNames, uint32_t *);
234 ordinal_table = RVA_TO_PTR(exports->AddressOfNameOrdinals, uint16_t *);
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, uint32_t 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 IMAGE_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 IMAGE_SECTION_HEADER *find_section(uint32_t rva)
335 IMAGE_SECTION_HEADER *section = IMAGE_SECTION_HDR(0);
336 for (i = 0; i < nt_hdr32->FileHeader.NumberOfSections; i++, section++)
337 if ((rva >= section->VirtualAddress) &&
338 (rva <= (section->VirtualAddress + section->SizeOfRawData)))
343 /* convert rva to pointer into loaded file */
345 rva_to_ptr(uint32_t rva)
347 IMAGE_SECTION_HEADER *section = find_section(rva);
348 return (section->PointerToRawData != 0)
349 ? (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);