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 %d.%d Copyright 1998, Anders Norlander\n"
145 "Changed 1999, Paul Sokolovsky\n"
146 "Changed 2008, Tor Lillqvist\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 to anorland@hem2.passagen.se,\n"
156 "Paul.Sokolovsky@technologist.com\n"
158 VER_MAJOR, VER_MINOR,
163 /* parse headers and build symbol tree */
167 dos_hdr = load_pe_image(filename);
170 fprintf(stderr, "%s: %s: could not load PE image\n",
171 program_name, filename);
175 nt_hdr32 = (PIMAGE_NT_HEADERS32) ((char *) dos_hdr + dos_hdr->e_lfanew);
176 nt_hdr64 = (PIMAGE_NT_HEADERS64) nt_hdr32;
178 if (nt_hdr32->FileHeader.Machine == IMAGE_FILE_MACHINE_I386) {
179 exp_rva = nt_hdr32->OptionalHeader.DataDirectory[0].VirtualAddress;
180 exp_size = nt_hdr32->OptionalHeader.DataDirectory[0].Size;
182 exp_rva = nt_hdr64->OptionalHeader.DataDirectory[0].VirtualAddress;
183 exp_size = nt_hdr64->OptionalHeader.DataDirectory[0].Size;
188 for (i = 0; i < nt_hdr32->FileHeader.NumberOfSections; i++)
190 section = IMAGE_SECTION_HDR(i);
191 printf("; %-8.8s: RVA: %08x, File offset: %08x\n",
193 section->VirtualAddress,
194 section->PointerToRawData);
198 /* Look for export section */
199 for (i = 0; i < nt_hdr32->FileHeader.NumberOfSections; i++)
201 section = IMAGE_SECTION_HDR(i);
202 if (memcmp(section->Name, exp_sign, sizeof(exp_sign)) == 0)
203 dump_exports(section->VirtualAddress, exp_size);
204 else if ((exp_rva >= section->VirtualAddress) &&
205 (exp_rva < (section->VirtualAddress + section->SizeOfRawData)))
206 dump_exports(exp_rva, exp_size);
213 /* dump exported symbols on stdout */
215 dump_exports(DWORD exports_rva, DWORD exports_size)
217 PIMAGE_SECTION_HEADER section;
218 PIMAGE_EXPORT_DIRECTORY exports;
222 DWORD *function_table;
224 static int first = 1;
226 section = find_section(exports_rva);
229 printf("; Reading exports from section: %s\n",
232 exports = RVA_TO_PTR(exports_rva, PIMAGE_EXPORT_DIRECTORY);
234 /* set up various pointers */
235 export_name = RVA_TO_PTR(exports->Name,char*);
236 ordinal_table = RVA_TO_PTR(exports->AddressOfNameOrdinals,WORD*);
237 name_table = RVA_TO_PTR(exports->AddressOfNames,DWORD*);
238 function_table = RVA_TO_PTR(exports->AddressOfFunctions,void*);
242 printf("; Export table: %s\n", export_name);
243 printf("; Ordinal base: %d\n", exports->Base);
244 printf("; Ordinal table RVA: %08x\n",
245 exports->AddressOfNameOrdinals);
246 printf("; Name table RVA: %07x\n",
247 exports->AddressOfNames);
248 printf("; Export address table RVA: %08x\n",
249 exports->AddressOfFunctions);
254 printf("LIBRARY %s\n", export_name);
259 printf("; LIBRARY %s\n", export_name);
261 for (i = 0; i < exports->NumberOfNames; i++)
263 dump_symbol(RVA_TO_PTR(name_table[i],char*),
264 ordinal_table[i] + exports->Base,
265 function_table[ordinal_table[i]]);
267 int f_off = ordinal_table[i];
269 if(function_table[f_off] >= exports_rva && function_table[f_off] < (exports_rva + exports_size) && verbose) {
270 printf(" ; Forwarder (%s)", RVA_TO_PTR(function_table[f_off], char*));
276 for (i = 0; i < exports->NumberOfFunctions; i++)
278 if ( (function_table[i] >= exports_rva) &&
279 (function_table[i] < (exports_rva + exports_size)))
281 int name_present = 0, n;
283 for(n = 0; n < exports->NumberOfNames; n++) {
284 if(ordinal_table[n] == i) {
291 dump_symbol(strchr(RVA_TO_PTR(function_table[i],char*), '.')+1, i + exports->Base, function_table[i]);
293 printf(" ; WARNING: Symbol name guessed from forwarder (%s)\n", RVA_TO_PTR(function_table[i], char*));
300 dump_symbol(char *name, int ord, DWORD rva)
303 str_tree *symbol = str_tree_find(symbols, name);
304 /* if a symbol was found, emit size of stack */
306 sprintf(s, "%s@%"PRIdPTR, name, (intptr_t)(symbol->extra));
308 sprintf(s, "%s", name);
312 printf("%-24s\t@%d", s, ord);
317 PIMAGE_SECTION_HEADER s=find_section(rva);
319 /* Stupid msvc doesn't have .bss section, it spews uninitilized data
322 if (!s) { printf(" DATA"); if (verbose) printf (" ; no section"); }
325 if (!(s->Characteristics&IMAGE_SCN_CNT_CODE)) printf(" DATA");
326 if (verbose) printf (" ; %.8s",s->Name);
331 printf(" ; RVA %08x", rva);
334 /* get section to which rva points */
335 PIMAGE_SECTION_HEADER
336 find_section(DWORD rva)
339 PIMAGE_SECTION_HEADER section = IMAGE_SECTION_HDR(0);
340 for (i = 0; i < nt_hdr32->FileHeader.NumberOfSections; i++, section++)
341 if ((rva >= section->VirtualAddress) &&
342 (rva <= (section->VirtualAddress + section->SizeOfRawData)))
347 /* convert rva to pointer into loaded file */
349 rva_to_ptr(DWORD rva)
351 PIMAGE_SECTION_HEADER section = find_section(rva);
352 if (section->PointerToRawData == 0)
355 return ((char *) dos_hdr + rva - (section->VirtualAddress - section->PointerToRawData));
358 /* Load a portable executable into memory */
360 load_pe_image(const char *filename)
367 PIMAGE_DOS_HEADER phdr;
370 if (stat(filename, &st) == -1)
376 phdr = (PIMAGE_DOS_HEADER) xmalloc(st.st_size);
378 f = fopen(filename, "rb");
387 if (fread(phdr, st.st_size, 1, f) != 1)
393 else if (memcmp(mz_sign, phdr, sizeof(mz_sign)) != 0)
395 fprintf(stderr, "No MZ signature\n");
399 else if (memcmp((char *) phdr + phdr->e_lfanew, pe_sign, sizeof(pe_sign)) != 0)
401 fprintf(stderr, "No PE signature\n");
410 /* parse headers to build symbol tree */
416 #define pclose _pclose
424 header = header_files;
428 /* construct command line */
429 cpp_cmd = strdup(cpp);
432 fprintf(stderr, "%s: out of memory\n", program_name);
435 len = strlen(cpp_cmd);
439 const char *fullname = find_file(header->s);
441 if (fullname == NULL)
446 tmp = strlen(fullname) + 10;
447 cpp_cmd = realloc(cpp_cmd, len + tmp);
450 fprintf(stderr, "%s: out of memory\n", program_name);
454 sprintf(cpp_cmd + len, " %s", fullname);
456 sprintf(cpp_cmd + len, " -include %s", fullname);
458 header = header->next;
463 printf("; %s\n", cpp_cmd);
466 Note: CRTDLL messes up stdout when popen is called so
467 if you try to pipe output through another program
468 with | it will hang. Redirect it to a file instead
469 and pass that file to the program (more,less or whatever).
470 This does not apply to cygwin.
472 f = popen(cpp_cmd, "r");
476 fprintf(stderr, "%s: %s: could not execute\n", program_name, cpp_cmd);
484 /* allocate memory; abort on failure */
486 *xmalloc(size_t count)
488 void *p = malloc(count);
491 fprintf(stderr, "%s: out of memory\n", program_name);
497 /* add string to end of list */
499 str_list_add(str_list **head, const char *s)
501 str_list *node = xmalloc(sizeof(str_list));
517 /* find a file in include path */
519 find_file(const char *name)
521 static char fullname[PATH_MAX];
522 FILE *f = fopen(name, "r");
523 str_list *path = inc_path;
531 strcpy(fullname, path->s);
532 strcat(fullname, "/");
533 strcat(fullname, name);
534 f = fopen(fullname, "r");
546 /* add a environment-style path list to list of include paths */
548 add_path_list(char *path)
555 if (*p == PATH_SEPARATOR)
558 str_list_add(&inc_path, path);
564 if (p[-1] != PATH_SEPARATOR)
565 str_list_add(&inc_path, path);