| /* | 
 |     gendef - Generate list of exported symbols from a Portable Executable. | 
 |     Copyright (C) 2009-2016  mingw-w64 project | 
 |  | 
 |     This program is free software: you can redistribute it and/or modify | 
 |     it under the terms of the GNU General Public License as published by | 
 |     the Free Software Foundation, either version 3 of the License, or | 
 |     (at your option) any later version. | 
 |  | 
 |     This program is distributed in the hope that it will be useful, | 
 |     but WITHOUT ANY WARRANTY; without even the implied warranty of | 
 |     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
 |     GNU General Public License for more details. | 
 |  | 
 |     You should have received a copy of the GNU General Public License | 
 |     along with this program.  If not, see <http://www.gnu.org/licenses/>. | 
 | */ | 
 | #ifdef HAVE_CONFIG_H | 
 | #include "config.h" | 
 | #endif | 
 | #include <stddef.h> | 
 | #include <stdio.h> | 
 | #include <stdlib.h> | 
 | #include <memory.h> | 
 | #include <string.h> | 
 | #include "compat_string.h" | 
 | #include "gendef.h" | 
 | #include "fsredir.h" | 
 | #ifdef HAVE_LIBMANGLE | 
 | #include <libmangle.h> | 
 | #endif | 
 |  | 
 | #define ENABLE_DEBUG 0 | 
 |  | 
 | #if ENABLE_DEBUG == 1 | 
 | #define PRDEBUG(ARG...)  fprintf(stderr,ARG) | 
 | #else | 
 | #define PRDEBUG(ARG...) do { } while(0) | 
 | #endif | 
 |  | 
 | static void decode_mangle (FILE *fp, const char *n); | 
 | static int load_pep (void); | 
 | static void do_pedef (void); | 
 | static void do_pepdef (void); | 
 | static void do_import_read32 (uint32_t va_imp, uint32_t sz_imp); | 
 | static void do_export_read (uint32_t va_exp,uint32_t sz_exp,int be64); | 
 | static void add_export_list (uint32_t ord,uint32_t func,const char *name, const char *forward,int be64,int beData); | 
 | static void dump_def (void); | 
 | static int disassembleRet (uint32_t func,uint32_t *retpop,const char *name, sImportname **ppimpname, int *seen_ret); | 
 | static size_t getMemonic (int *aCode,uint32_t pc,volatile uint32_t *jmp_pc,const char *name, sImportname **ppimpname); | 
 |  | 
 | static sImportname *imp32_add (const char *dll, const char *name, uint32_t addr, uint16_t ord); | 
 | static void imp32_free (void); | 
 | static sImportname *imp32_findbyaddress (uint32_t addr); | 
 |  | 
 | static sImportname *theImports = NULL; | 
 |  | 
 | static void *map_va (uint32_t va); | 
 | static int is_data (uint32_t va); | 
 | static int is_reloc (uint32_t va); | 
 | static int has_atdecoration (void); | 
 |  | 
 | static int disassembleRetIntern (uint32_t pc, uint32_t *retpop, sAddresses *seen, sAddresses *stack, | 
 | 				 int *hasret, int *atleast_one, const char *name, sImportname **ppimpname); | 
 | static sAddresses*init_addr (void); | 
 | static void dest_addr (sAddresses *ad); | 
 | static int push_addr (sAddresses *ad,uint32_t val); | 
 | static int pop_addr (sAddresses *ad,uint32_t *val); | 
 |  | 
 | static sExportName *gExp = NULL; | 
 | static sExportName *gExpTail = NULL; | 
 | char *fninput; | 
 | char *fnoutput; | 
 | char *fndllname; | 
 |  | 
 | size_t gDta_size; | 
 | unsigned char *gDta; | 
 | PIMAGE_DOS_HEADER gMZDta; | 
 | PIMAGE_NT_HEADERS32 gPEDta; | 
 | PIMAGE_NT_HEADERS64 gPEPDta; | 
 |  | 
 | #ifdef REDIRECTOR | 
 | static int use_redirector = 0; /* Use/Disable FS redirector */ | 
 | #endif | 
 |  | 
 | static int std_output = 0; | 
 | static int assume_stdcall = 0; /* Set to one, if function symbols should be assumed to have stdcall.  */ | 
 | static int no_forward_output = 0; /* Set to one, if in .def files forwarders shouldn't be displayed.  */ | 
 |  | 
 | static Gendefopts *chain_ptr = NULL; | 
 |  __attribute__((noreturn)) static void show_usage (void); | 
 | static int opt_chain (const char *, const char *); | 
 |  | 
 | static int | 
 | opt_chain (const char *opts, const char *next) | 
 | { | 
 |   static Gendefopts *prev, *current; | 
 |   char *r1, *r2; | 
 |    | 
 |   if (!strncmp (opts, "-", 2)) | 
 |     { | 
 |       std_output = 1; | 
 |       return 0; | 
 |     } | 
 |   if (!strcmp (opts, "--help") || !strcmp (opts, "-h")) | 
 |     { | 
 |       show_usage(); | 
 |       return 0; | 
 |     } | 
 |   if (!strcmp (opts, "--assume-stdcall") || !strcmp (opts, "-a")) | 
 |     { | 
 |       assume_stdcall = 1; | 
 |       return 0; | 
 |     } | 
 |   if (!strcmp (opts, "--include-def-path") || !strcmp (opts, "-I")) | 
 |     { | 
 |       if (!next) | 
 |         { | 
 | 	  fprintf (stderr, "Error: %s expects path as next arguement.", opts); | 
 | 	  return 0; | 
 |         } | 
 |       gendef_addpath_def (next); | 
 |       return 1; | 
 |     } | 
 |   if (!strcmp (opts, "--no-include-current-dir")) | 
 |     { | 
 |       gendef_no_include_current_dir (); | 
 |       return 0; | 
 |     } | 
 |   if (!strcmp (opts, "--no-forward-output") || !strcmp (opts, "-f")) | 
 |     { | 
 |       no_forward_output = 1; | 
 |       return 0; | 
 |     } | 
 |  | 
 | #ifdef REDIRECTOR | 
 |   if (!strcmp (opts, "--disable-fs-redirector") || !strcmp (opts, "-r")) | 
 |     { | 
 |       use_redirector = 1; | 
 |       return 0; | 
 |     } | 
 | #endif | 
 |  | 
 |   current = malloc (sizeof(Gendefopts)); | 
 |   if (current) | 
 |     { | 
 |       memset (current, 0, sizeof (Gendefopts)); | 
 |       current->next = NULL; | 
 |  | 
 |       if (!prev) | 
 |         chain_ptr = current; | 
 |       else | 
 |         prev->next = current; | 
 |       r1 = strrchr (opts,'/'); | 
 |       r2 = strrchr (opts,'\\'); | 
 |       current->fninput = strdup (opts); | 
 |        | 
 |       if (!r1 && r2 != NULL) | 
 |         r1 = r2 + 1; | 
 |       else if(r1 == NULL && r2 == NULL) | 
 |         r1 = current->fninput; | 
 |       else if (r2 != NULL && r1 != NULL && r1 < r2) | 
 |         r1 = r2 + 1; | 
 |       else | 
 |         r1++; | 
 |       current->fnoutput = (char *) malloc (strlen (current->fninput) + 5); | 
 |       strcpy (current->fnoutput,r1); | 
 |  | 
 |       r1 = strrchr (current->fnoutput,'.'); | 
 |       if (r1) | 
 |         strcpy (r1,".def"); | 
 |       else | 
 |         strcat (current->fnoutput,".def"); | 
 |       prev = current; | 
 |    } | 
 |   return 0; | 
 | } | 
 |  | 
 | void | 
 | show_usage (void) | 
 | { | 
 |   fprintf (stderr, "Usage: gendef [OPTION]... [DLL]...\n"); | 
 |   fprintf (stderr, "Dumps DLL exports information from PE32/PE32+ executables\n"); | 
 |   fprintf (stderr, "\n"); | 
 |   fprintf (stderr, "Options:\n" | 
 |     "  -                        Dump to stdout\n" | 
 |     "  -h, --help               Show this help.\n" | 
 |     "  -a, --assume-stdcall     Assume functions with ambiguous call\n" | 
 |     "                           convention as stdcall.\n" | 
 |     "  -I, --include-def-path <path>\n" | 
 |     "                           Add additional search paths to find\n" | 
 |     "                           hint .def files.\n" | 
 |     "  --no-include-current-dir Don't search current directory to find\n" | 
 |     "                           hint .def files.\n" | 
 |     "  -f, --no-forward-output  Don't output forwarders in .def file\n" | 
 | #ifdef REDIRECTOR | 
 |     "  -r, --disable-fs-redirector\n" | 
 |     "                           Disable Win64 FS redirection, for 32-bit\n" | 
 |     "                           gendef on 64-bit Windows\n" | 
 | #endif | 
 |   ); | 
 |   fprintf (stderr, "\n"); | 
 |   fprintf (stderr, "Usage example: \n" | 
 |                    "  By default, the output files are named after their DLL counterparts\n" | 
 |                    "  gendef MYDLL.DLL     Produces MYDLL.def\n" | 
 |                    "  gendef - MYDLL.DLL   Prints the exports to stdout\n"); | 
 |   fprintf (stderr, "\nVersion %s\n", VERSION); | 
 |   fprintf (stderr, "\nReport bugs to <mingw-w64-public@lists.sourceforge.net>\n"); | 
 |   exit (0); | 
 | } | 
 |  | 
 | int main(int argc,char **argv) | 
 | { | 
 |   int i; | 
 |   Gendefopts *opt, *next; | 
 |  | 
 |   if (argc < 2) | 
 |   { | 
 |     show_usage (); | 
 |     return 0; | 
 |   } | 
 |  | 
 |   for (i = 1; i < argc; i++) | 
 |     i += opt_chain (argv[i], ((i+1) < argc ? argv[i+1] : NULL)); | 
 | #ifdef REDIRECTOR | 
 |   doredirect(use_redirector); | 
 | #endif | 
 |   opt = chain_ptr; | 
 |   while (opt) | 
 |     { | 
 |       fninput = opt->fninput; | 
 |       fnoutput = opt->fnoutput; | 
 |  | 
 |       if (load_pep ()) | 
 |         { | 
 | 	  if (gPEDta || gPEPDta) | 
 | 	    { | 
 | 	      if (gPEDta) | 
 | 		do_pedef (); | 
 | 	      else | 
 | 		do_pepdef (); | 
 | 	      dump_def (); | 
 | 	    } | 
 | 	} | 
 |       if (fndllname) | 
 | 	free (fndllname); | 
 |       fndllname = NULL; | 
 |       if (gDta) | 
 | 	{ | 
 | 	  free (gDta); | 
 | 	  gDta = NULL; | 
 | 	} | 
 |       next = opt->next; | 
 |       free(opt->fninput); | 
 |       free(opt->fnoutput); | 
 |       free(opt); | 
 |       opt = next; | 
 |     } | 
 |   imp32_free (); | 
 |   return 0; | 
 | } | 
 |  | 
 | static int | 
 | load_pep (void) | 
 | { | 
 |   FILE *fp = fopen (fninput, "rb"); | 
 |  | 
 |   if (!fp) | 
 |     { | 
 |       fprintf (stderr, "*** [%s] failed to open()\n", fninput); | 
 |       return 0; | 
 |     } | 
 |   fseek (fp, 0, SEEK_END); | 
 |   gDta_size = (size_t) ftell (fp); | 
 |   if (gDta_size > 0) { | 
 |     fseek (fp,0,SEEK_SET); | 
 |     gDta = (unsigned char *) malloc (gDta_size + 1); | 
 |     if (gDta) | 
 |       { | 
 |         if (fread (gDta, gDta_size, 1, fp) != 1) | 
 | 	  { | 
 | 	    free (gDta); | 
 | 	    gDta = NULL; | 
 | 	  } | 
 | 	else | 
 |           gDta[gDta_size] = 0; | 
 |     } | 
 |   } | 
 |   fclose (fp); | 
 |   if (!gDta) | 
 |     { | 
 |       fprintf (stderr, "*** [%s] unable to allocate %lu bytes\n", fninput, | 
 | 	       (unsigned long) gDta_size); | 
 |       return 0; | 
 |     } | 
 |   gMZDta = (PIMAGE_DOS_HEADER) gDta; | 
 |   if (gDta_size < sizeof(IMAGE_DOS_HEADER) || gDta[0]!='M' || gDta[1]!='Z' | 
 |       || gMZDta->e_lfanew <= 0 | 
 |       || gMZDta->e_lfanew >= (int32_t) gDta_size) | 
 |   { | 
 |     fprintf(stderr,"*** [%s] not a PE(+) file\n", fninput); | 
 |     free(gDta); | 
 |     gDta = NULL; | 
 |     return 0; | 
 |   } | 
 |   gPEDta = (PIMAGE_NT_HEADERS32) &gDta[gMZDta->e_lfanew]; | 
 |   gPEPDta = (PIMAGE_NT_HEADERS64) gPEDta; | 
 |   if (gPEDta->Signature != IMAGE_NT_SIGNATURE) | 
 |     { | 
 |       fprintf (stderr, "*** [%s] no PE(+) signature\n", fninput); | 
 |       free (gDta); | 
 |       gDta = NULL; | 
 |       gPEPDta = NULL; | 
 |       gPEDta = NULL; | 
 |       return 0; | 
 |     } | 
 |   if (gPEDta->FileHeader.SizeOfOptionalHeader >= offsetof(IMAGE_OPTIONAL_HEADER32, DataDirectory) | 
 |       && gPEDta->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) | 
 |     { | 
 |       gPEPDta = NULL; | 
 |       fprintf (stderr, " * [%s] Found PE image\n", fninput); | 
 |     } | 
 |   else if (gPEDta->FileHeader.SizeOfOptionalHeader >= offsetof(IMAGE_OPTIONAL_HEADER32, DataDirectory) | 
 |       && gPEDta->OptionalHeader.Magic == 0 && gPEDta->FileHeader.Machine == 0x014c /* IMAGE_FILE_MACHINE_I386 */) | 
 |     { | 
 |       gPEPDta = NULL; | 
 |       fprintf (stderr, " * [%s] Found PE image for I386 with zeroed NT magic\n", fninput); | 
 |     } | 
 |   else if (gPEPDta->FileHeader.SizeOfOptionalHeader >= offsetof(IMAGE_OPTIONAL_HEADER64, DataDirectory) | 
 |     && gPEPDta->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC) | 
 |     { | 
 |       gPEDta = NULL; | 
 |       fprintf (stderr, " * [%s] Found PE+ image\n", fninput); | 
 |     } | 
 |   else | 
 |     { | 
 |       free (gDta); | 
 |       gDta = NULL; | 
 |       fprintf (stderr, "*** [%s] no PE(+) optional header\n", fninput); | 
 |       gPEPDta = NULL; | 
 |       gPEDta = NULL; | 
 |       return 0; | 
 |     } | 
 |   return 1; | 
 | } | 
 |  | 
 | static int | 
 | is_data (uint32_t va) | 
 | { | 
 |   PIMAGE_SECTION_HEADER sec; | 
 |   uint32_t sec_cnt,i; | 
 |  | 
 |   /* If export va is directly relocated, so it must be data.  */   | 
 |   if (is_reloc (va)) | 
 |     return 1; | 
 |    | 
 |   if (gPEDta) | 
 |     { | 
 |       sec_cnt = gPEDta->FileHeader.NumberOfSections; | 
 |       sec = IMAGE_FIRST_SECTION(gPEDta); | 
 |     } | 
 |   else | 
 |     { | 
 |       sec_cnt = gPEPDta->FileHeader.NumberOfSections; | 
 |       sec = IMAGE_FIRST_SECTION(gPEPDta); | 
 |     } | 
 |   if (!sec) | 
 |     return 0; | 
 |   for (i = 0;i < sec_cnt;i++) | 
 |     { | 
 |       if (va >= sec[i].VirtualAddress && va < (sec[i].VirtualAddress+sec[i].Misc.VirtualSize)) | 
 |         break; | 
 |     } | 
 |   if (i == sec_cnt) | 
 |     return 0;  | 
 |   if ((sec[i].Characteristics & (IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_CNT_CODE)) != 0) | 
 |     return 0; | 
 |   if ((sec[i].Characteristics & IMAGE_SCN_MEM_DISCARDABLE) != 0) | 
 |     return 1; | 
 |   if ((sec[i].Characteristics & IMAGE_SCN_MEM_READ) ==0) | 
 |     return 0; | 
 |   if ((sec[i].Characteristics & (IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_LNK_COMDAT)) != 0) | 
 |     return 1; | 
 |   return 1; | 
 | } | 
 |  | 
 | static int | 
 | is_reloc (uint32_t va) | 
 | { | 
 |   uint32_t va_rel = 0; | 
 |   uint32_t sz_rel = 0; | 
 |   uint32_t pos; | 
 |   unsigned char *p; | 
 |   PIMAGE_BASE_RELOCATION brel; | 
 |  | 
 |   if (gPEDta) | 
 |     { | 
 |       if (gPEDta->OptionalHeader.NumberOfRvaAndSizes > IMAGE_DIRECTORY_ENTRY_BASERELOC) | 
 |         { | 
 |           va_rel = gPEDta->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress; | 
 |           sz_rel = gPEDta->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size; | 
 |         } | 
 |     } | 
 |   else | 
 |     { | 
 |       if (gPEPDta->OptionalHeader.NumberOfRvaAndSizes > IMAGE_DIRECTORY_ENTRY_BASERELOC) | 
 |         { | 
 |           va_rel = gPEPDta->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress; | 
 |           sz_rel = gPEPDta->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size; | 
 |         } | 
 |     } | 
 |   if (va_rel == 0 || sz_rel < IMAGE_SIZEOF_BASE_RELOCATION) | 
 |     return 0; | 
 |   p = (unsigned char *) map_va (va_rel); | 
 |   for (pos = 0; pos < sz_rel;) | 
 |     { | 
 |       uint16_t *r; | 
 |       uint32_t nums, j; | 
 |       if ((sz_rel - pos) < IMAGE_SIZEOF_BASE_RELOCATION) | 
 |         break; | 
 |       brel = (PIMAGE_BASE_RELOCATION) &p[pos]; | 
 |       if (brel->SizeOfBlock == 0) | 
 |          break; | 
 |       pos += IMAGE_SIZEOF_BASE_RELOCATION; | 
 |       nums = (brel->SizeOfBlock - IMAGE_SIZEOF_BASE_RELOCATION) / 2; | 
 |       r = (uint16_t *) &p[pos]; | 
 |       if (va >= brel->VirtualAddress && va < (brel->VirtualAddress + 0x1008)) | 
 |         { | 
 |           for (j = 0; j < nums; j++) | 
 |             { | 
 |               uint32_t relsz = 0; | 
 |               uint32_t offs = (uint32_t) (r[j] & 0xfff) + brel->VirtualAddress; | 
 |               uint16_t typ = (r[j] >> 12) & 0xf; | 
 |               if (typ == IMAGE_REL_BASED_HIGHADJ) | 
 |                 j++; | 
 |               switch (typ) | 
 |                 { | 
 |                 case IMAGE_REL_BASED_HIGHLOW: | 
 |                   relsz = 4; | 
 |                   break; | 
 |                 case IMAGE_REL_BASED_DIR64: | 
 |                   relsz = 8; | 
 |                   break; | 
 |                 } | 
 |               if (relsz != 0 && va >= offs && va < (offs + relsz)) | 
 |                 return 1; | 
 |             } | 
 |         } | 
 |       pos += (brel->SizeOfBlock - IMAGE_SIZEOF_BASE_RELOCATION); | 
 |     } | 
 |   return 0; | 
 | } | 
 |  | 
 | static void * | 
 | map_va (uint32_t va) | 
 | { | 
 |   PIMAGE_SECTION_HEADER sec; | 
 |   uint32_t sec_cnt,sz,i; | 
 |   char *dptr; | 
 |  | 
 |   if (gPEDta) | 
 |     { | 
 |       sec_cnt = gPEDta->FileHeader.NumberOfSections; | 
 |       sec = IMAGE_FIRST_SECTION(gPEDta); | 
 |     } | 
 |   else | 
 |     { | 
 |       sec_cnt = gPEPDta->FileHeader.NumberOfSections; | 
 |       sec = IMAGE_FIRST_SECTION(gPEPDta); | 
 |     } | 
 |   for (i = 0;i < sec_cnt;i++) | 
 |     { | 
 |       sz = sec[i].Misc.VirtualSize; | 
 |       if (!sz) sz = sec[i].SizeOfRawData; | 
 |       if (va >= sec[i].VirtualAddress && va < (sec[i].VirtualAddress+sz)) | 
 |         { | 
 |           dptr = (char *) &gDta[va-sec[i].VirtualAddress+sec[i].PointerToRawData]; | 
 |           return (void *)dptr; | 
 |         } | 
 |     } | 
 |   return NULL; | 
 | } | 
 |  | 
 | /* For pep we can take the exports itself, there is no additional decoration necessary.  */ | 
 | static void | 
 | do_pepdef (void) | 
 | { | 
 |   uint32_t va_exp = 0; | 
 |   uint32_t sz_exp = 0; | 
 |  | 
 |   if (gPEPDta->OptionalHeader.NumberOfRvaAndSizes > IMAGE_DIRECTORY_ENTRY_EXPORT) | 
 |     { | 
 |       va_exp = gPEPDta->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress; | 
 |       sz_exp = gPEPDta->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size; | 
 |     } | 
 |  | 
 |   do_export_read (va_exp, sz_exp, 1); | 
 | } | 
 |  | 
 | static void | 
 | do_pedef (void) | 
 | { | 
 |   uint32_t va_exp = 0; | 
 |   uint32_t sz_exp = 0; | 
 |   uint32_t va_imp = 0; | 
 |   uint32_t sz_imp = 0; | 
 |  | 
 |   if (gPEDta->OptionalHeader.NumberOfRvaAndSizes > IMAGE_DIRECTORY_ENTRY_EXPORT) | 
 |     { | 
 |       va_exp = gPEDta->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress; | 
 |       sz_exp = gPEDta->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size; | 
 |     } | 
 |  | 
 |   if (gPEDta->OptionalHeader.NumberOfRvaAndSizes > IMAGE_DIRECTORY_ENTRY_IMPORT) | 
 |     { | 
 |       va_imp = gPEDta->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress; | 
 |       sz_imp = gPEDta->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size; | 
 |     } | 
 |  | 
 |   imp32_free (); | 
 |   do_import_read32 (va_imp, sz_imp); | 
 |   do_export_read (va_exp, sz_exp, 0); | 
 | } | 
 |  | 
 | static void | 
 | do_import_read32 (uint32_t va_imp, uint32_t sz_imp) | 
 | { | 
 |   IMAGE_IMPORT_DESCRIPTOR *pid; | 
 |   if (!sz_imp || !va_imp) | 
 |     return; | 
 |   pid = (IMAGE_IMPORT_DESCRIPTOR *) map_va (va_imp); | 
 |   while (pid != NULL && sz_imp >= 20 && pid->Name != 0 && pid->OriginalFirstThunk != 0) | 
 |     { | 
 |       uint32_t index = 0; | 
 |       PIMAGE_THUNK_DATA32 pIAT; | 
 |       PIMAGE_THUNK_DATA32 pFT; | 
 |       char *imp_name = (char *) map_va (pid->Name); | 
 |  | 
 |       for (;;) { | 
 | 	char *fctname; | 
 | 	pIAT = (PIMAGE_THUNK_DATA32) map_va (pid->OriginalFirstThunk + index); | 
 | 	pFT = (PIMAGE_THUNK_DATA32) map_va (pid->FirstThunk + index); | 
 | 	if (pIAT->u1.Ordinal == 0 || pFT->u1.Ordinal == 0) | 
 | 	  break; | 
 | 	if (IMAGE_SNAP_BY_ORDINAL32 (pIAT->u1.Ordinal)) | 
 | 	  fctname = NULL; | 
 | 	else | 
 | 	  fctname = (char *) map_va (pIAT->u1.Function + 2); | 
 | 	if (fctname) | 
 | 	  imp32_add (imp_name, fctname, | 
 | 	  //pid->OriginalFirstThunk + index + gPEDta->OptionalHeader.ImageBase, | 
 | 	  pid->FirstThunk + index + gPEDta->OptionalHeader.ImageBase, | 
 | 	    *((uint16_t *) map_va (pIAT->u1.Function))); | 
 | 	index += 4; | 
 |       } | 
 |       sz_imp -= 20; | 
 |       va_imp += 20; | 
 |       if (sz_imp >= 20) | 
 | 	pid = (IMAGE_IMPORT_DESCRIPTOR *) map_va (va_imp); | 
 |     } | 
 | } | 
 |  | 
 | static sImportname * | 
 | imp32_findbyaddress (uint32_t addr) | 
 | { | 
 |   sImportname *h = theImports; | 
 |   while (h != NULL && h->addr_iat != addr) | 
 |     h = h->next; | 
 |   return h; | 
 | } | 
 |  | 
 | static void | 
 | imp32_free (void) | 
 | { | 
 |   while (theImports != NULL) | 
 |     { | 
 |       sImportname *h = theImports; | 
 |       theImports = theImports->next; | 
 |       if (h->dll) | 
 | 	free (h->dll); | 
 |       if (h->name) | 
 | 	free (h->name); | 
 |       free (h); | 
 |     } | 
 | } | 
 |  | 
 | static sImportname * | 
 | imp32_add (const char *dll, const char *name, uint32_t addr, uint16_t ord) | 
 | { | 
 |   sImportname *n = (sImportname *) malloc (sizeof (sImportname)); | 
 |   memset (n, 0, sizeof (sImportname)); | 
 |   n->dll = strdup (dll); | 
 |   n->name = strdup (name); | 
 |   n->ord = ord; | 
 |   n->addr_iat = addr; | 
 |   n->next = theImports; | 
 |   theImports = n; | 
 |   return n; | 
 | } | 
 |  | 
 | static void | 
 | do_export_read (uint32_t va_exp, uint32_t sz_exp, int be64) | 
 | { | 
 |   uint32_t i; | 
 |   PIMAGE_EXPORT_DIRECTORY exp_dir; | 
 |   uint32_t *functions; | 
 |   uint16_t *ordinals; | 
 |   uint32_t *name; | 
 |  | 
 |   if (va_exp == 0 || sz_exp == 0) | 
 |     return; | 
 |   exp_dir = (PIMAGE_EXPORT_DIRECTORY) map_va (va_exp); | 
 |   PRDEBUG(" * export directory at VA = 0x%x size=0x%x\n", (unsigned int) va_exp, (unsigned int) sz_exp); | 
 |   fndllname = strdup ((char *) map_va (exp_dir->Name)); | 
 |   PRDEBUG(" * Name: %s\n * Base: %u\n", fndllname, (unsigned int) exp_dir->Base); | 
 |   functions = (uint32_t *) map_va (exp_dir->AddressOfFunctions); | 
 |   ordinals = (uint16_t *) map_va (exp_dir->AddressOfNameOrdinals); | 
 |   name = (uint32_t *) map_va (exp_dir->AddressOfNames); | 
 |    | 
 |   for (i = 0;i < exp_dir->NumberOfFunctions;i++) | 
 |     { | 
 |       uint32_t entryPointRVA = functions[i]; | 
 |       uint32_t j; | 
 |       char *fname; | 
 |       uint32_t ord; | 
 |       fname = NULL; | 
 |       if (!entryPointRVA) | 
 |         continue; | 
 |       ord = i + exp_dir->Base; | 
 |       for (j = 0;j < exp_dir->NumberOfNames;j++) | 
 |         if (ordinals[j]==i) | 
 |           fname = (char *) map_va (name[j]); | 
 |       if (entryPointRVA >= va_exp && entryPointRVA <= (va_exp + sz_exp)) | 
 |         add_export_list (ord, 0, fname,(char *) map_va (entryPointRVA), be64, 0); | 
 |       else | 
 |         add_export_list(ord, entryPointRVA, fname, NULL, be64, is_data (entryPointRVA)); | 
 |     } | 
 | } | 
 |  | 
 | static void | 
 | add_export_list(uint32_t ord,uint32_t func,const char *name, const char *forward,int be64,int beData) | 
 | { | 
 |   sExportName *exp = NULL; | 
 |  | 
 |   if (!name) | 
 |     name = ""; | 
 |   if (!forward) | 
 |     forward = ""; | 
 |   exp = (sExportName *) malloc (sizeof (sExportName) + strlen (name) + strlen (forward) + 2); | 
 |   if (!exp) | 
 |     return; | 
 |   exp->name = (char *) &exp[1]; | 
 |   exp->forward = exp->name + strlen (name) + 1; | 
 |   strcpy (exp->name, name); | 
 |   strcpy (exp->forward, forward); | 
 |   exp->next = NULL; | 
 |   exp->ord = ord; | 
 |   exp->func = func; | 
 |   exp->be64 = be64; | 
 |   exp->beData = beData; | 
 |   exp->retpop = (uint32_t)-1; | 
 |   if (gExpTail) | 
 |     gExpTail->next = exp; | 
 |   else | 
 |     gExp = exp; | 
 |   gExpTail = exp; | 
 | } | 
 |  | 
 | static void | 
 | dump_def (void) | 
 | { | 
 |   sExportName *exp; | 
 |   FILE *fp; | 
 |  | 
 |   if (!fndllname || gExp == NULL) | 
 |     return; | 
 |   if (!std_output) | 
 |     fp = fopen(fnoutput,"wt"); | 
 |   else | 
 |     fp = stdout; | 
 |   if(!fp) { | 
 |     fprintf(stderr," * failed to create %s ...\n",fnoutput); | 
 |     return; | 
 |   } | 
 |   fprintf (fp,";\n; Definition file of %s\n; Automatic generated by gendef %s\n; written by Kai Tietz 2008\n; The def file has to be processed by --kill-at (-k) option of dlltool or ld\n;\n", | 
 |     fndllname, VERSION); | 
 |   fprintf (fp,"LIBRARY \"%s\"\nEXPORTS\n",fndllname); | 
 |   while ((exp = gExp) != NULL) | 
 |     { | 
 |       sImportname *pimpname; | 
 |       int seen_ret; | 
 |       seen_ret = 1; | 
 |       gExp = exp->next; | 
 |       int name_has_at_suffix = 0; | 
 |       int name_has_fastcall = 0; | 
 |       if (exp->name[0] == '?' && exp->name[1] == '?') | 
 |         { | 
 |           if (!strncmp (exp->name, "??_7", 4)) | 
 | 	    exp->beData = 1; | 
 |         } | 
 |       pimpname = NULL; | 
 |       if (!exp->beData && !exp->be64 && exp->func != 0) | 
 | 	{ | 
 | 	  seen_ret = 0; | 
 | 	  exp->beData = disassembleRet (exp->func, &exp->retpop, exp->name, &pimpname, &seen_ret); | 
 |         } | 
 |       if (!exp->be64 && exp->retpop == (uint32_t) -1 && pimpname) | 
 | 	{ | 
 | 	  int isD = 0; | 
 | 	  uint32_t at = 0; | 
 | 	  if (gendef_getsymbol_info (pimpname->dll, pimpname->name, &isD, &at)) | 
 | 	    { | 
 | 	      exp->beData = isD; | 
 | 	      if (!isD) | 
 | 		exp->retpop = at; | 
 | 	    } | 
 | 	} | 
 |       else if (exp->func == 0 && !exp->beData) | 
 | 	{ | 
 | 	  int isD = 0; | 
 | 	  uint32_t at = 0; | 
 | 	  if (gendef_getsymbol_info (exp->forward, NULL, &isD, &at)) | 
 | 	    { | 
 | 	      exp->beData = isD; | 
 | 	      if (!isD) | 
 | 	        exp->retpop = at; | 
 | 	    } | 
 | 	} | 
 |  | 
 |       if (exp->be64) | 
 |         exp->retpop = 0; | 
 |  | 
 |       if (exp->name[0] == '?') | 
 |         { | 
 |           decode_mangle (fp, exp->name); | 
 |         } | 
 |  | 
 |       if ((exp->name[0] == '_' || exp->name[0] == '@') && !exp->be64 && has_atdecoration()) | 
 |         { | 
 |           char at_suffix[12]; | 
 |           unsigned int retpop = exp->retpop != (uint32_t) -1 ? exp->retpop : 0; | 
 |           int name_len = strlen(exp->name); | 
 |           if (exp->name[0] == '_') | 
 |             { | 
 |               int at_suffix_len = sprintf(at_suffix, "@%u", retpop); | 
 |               if (name_len > at_suffix_len && memcmp(&exp->name[name_len-at_suffix_len], at_suffix, at_suffix_len) == 0) | 
 |                 name_has_at_suffix = 1; | 
 |             } | 
 |           else if (exp->name[0] == '@') | 
 |             { | 
 |               if (retpop == 0) | 
 |                 { | 
 |                   if (name_len > 2 && exp->name[name_len-2] == '@' && (exp->name[name_len-1] == '0' || exp->name[name_len-1] == '4' || exp->name[name_len-1] == '8')) | 
 |                     name_has_fastcall = 1; | 
 |                 } | 
 |               else | 
 |                 { | 
 |                   int at_suffix_len = sprintf(at_suffix, "@%u", retpop+8); | 
 |                   if (name_len > at_suffix_len && memcmp(&exp->name[name_len-at_suffix_len], at_suffix, at_suffix_len) == 0) | 
 |                     name_has_fastcall = 1; | 
 |                 } | 
 |             } | 
 |         } | 
 |       if (exp->name[0] == 0) | 
 |         fprintf (fp, "ord_%u", (unsigned int) exp->ord); | 
 |       else | 
 |         { | 
 |           const char *quote = strchr (exp->name, '.') ? "\"" : ""; | 
 |           const char *import_name = exp->name; | 
 |           if (name_has_at_suffix) | 
 |             import_name++; | 
 |           fprintf (fp, "%s%s%s", quote, import_name, quote); | 
 |         } | 
 |  | 
 |       if (exp->retpop != (uint32_t) -1 && !exp->be64 && has_atdecoration()) | 
 |         { | 
 |           if (exp->name[0]=='?') | 
 |             fprintf(fp," ; has WINAPI (@%u)", (unsigned int) exp->retpop); | 
 |           else if (!name_has_at_suffix && !name_has_fastcall) | 
 |             fprintf(fp,"@%u", (unsigned int) exp->retpop); | 
 |         } | 
 |       if (exp->func == 0 && no_forward_output == 0) | 
 | 	fprintf (fp, " = %s", exp->forward); | 
 |       if (exp->name[0] == 0) | 
 |         fprintf(fp," @%u NONAME", (unsigned int) exp->ord); | 
 |       if (exp->beData) | 
 |         fprintf(fp," DATA"); | 
 |       if (name_has_at_suffix || name_has_fastcall) | 
 |         { | 
 |           const char *quote = strchr (exp->name, '.') ? "\"" : ""; | 
 |           fprintf(fp, " == %s%s%s", quote, exp->name, quote); | 
 |         } | 
 |  | 
 |       if (exp->retpop != (uint32_t) -1 || (exp->retpop == 0 && exp->be64) || !has_atdecoration ()) | 
 | 	{ | 
 | 	} | 
 |       else if (pimpname) | 
 |         { | 
 | 	  fprintf (fp, " ; Check!!! return value is from %s in %s (ordinal %u)", | 
 | 	    pimpname->name, pimpname->dll, pimpname->ord); | 
 |         } | 
 |       else if (exp->func == 0 && !exp->beData) | 
 | 	{ | 
 | 	  fprintf (fp, " ; Check!!! forwards to %s", exp->forward); | 
 | 	} | 
 |       else if (seen_ret == 0 && !exp->beData) | 
 |         { | 
 | 	  fprintf (fp, " ; Check!!! Couldn't determine function argument count. Function doesn't return."); | 
 |         } | 
 |       fprintf(fp,"\n"); | 
 |       free (exp); | 
 |     } | 
 |   gExpTail=NULL; | 
 |   if (!std_output) | 
 |     fclose(fp); | 
 | } | 
 |  | 
 | static sAddresses * | 
 | init_addr (void) | 
 | { | 
 |   sAddresses *r = (sAddresses*) malloc (sizeof (sAddresses)); | 
 |   r->max = 8; | 
 |   r->cnt = 0; | 
 |   r->ptrs = (uint32_t *) malloc (sizeof (uint32_t) * 8); | 
 |   r->idx = 0; | 
 |   return r; | 
 | } | 
 |  | 
 | static void | 
 | dest_addr (sAddresses *ad) | 
 | { | 
 |   free (ad->ptrs); | 
 |   free (ad); | 
 | } | 
 |  | 
 | static int | 
 | push_addr (sAddresses *ad, uint32_t val) | 
 | { | 
 |   uint32_t i; | 
 |  | 
 |   for (i = 0;i < ad->cnt; i++) | 
 |     { | 
 |       if (ad->ptrs[i] == val) | 
 |         return 0; | 
 |     } | 
 |   if (ad->max == ad->cnt) | 
 |     { | 
 |       uint32_t *p = (uint32_t *) malloc (sizeof (uint32_t) * (ad->max + 8)); | 
 |  | 
 |       memcpy (p, ad->ptrs, sizeof (uint32_t) * ad->max); | 
 |       ad->max += 8; | 
 |       free (ad->ptrs); | 
 |       ad->ptrs = p; | 
 |     } | 
 |   ad->ptrs[ad->cnt++] = val; | 
 |   return 1; | 
 | } | 
 |  | 
 | static int | 
 | pop_addr (sAddresses *ad, uint32_t *val) | 
 | { | 
 |   if (!ad || ad->idx == ad->cnt) | 
 |     return 0; | 
 |   ad->idx++; | 
 |   *val = ad->ptrs[ad->idx-1]; | 
 |   return 1; | 
 | } | 
 |  | 
 | static int | 
 | has_atdecoration (void) | 
 | { | 
 |   return (gPEDta && gPEDta->FileHeader.Machine == 0x014c /* IMAGE_FILE_MACHINE_I386 */); | 
 | } | 
 |  | 
 | /* exp->beData */ | 
 | static int | 
 | disassembleRet (uint32_t func, uint32_t *retpop, const char *name, sImportname **ppimpname, int *seen_ret) | 
 | { | 
 |   sAddresses *seen = init_addr (); | 
 |   sAddresses *stack = init_addr (); | 
 |   uint32_t pc; | 
 |   int hasret = 0; | 
 |   int atleast_one = 0; | 
 |  | 
 |   if (!has_atdecoration()) | 
 |   { | 
 |     *retpop = 0; | 
 |     return 0; | 
 |   } | 
 |   *retpop = (uint32_t) -1; | 
 |   push_addr (stack, func); | 
 |  | 
 |   while (!hasret && pop_addr (stack,&pc)) | 
 |     { | 
 |       if (disassembleRetIntern (pc, retpop, seen, stack, &hasret, &atleast_one, name, ppimpname)) | 
 |         break; | 
 |     } | 
 |   *seen_ret = hasret; | 
 |   dest_addr (seen); | 
 |   dest_addr (stack); | 
 |   return (atleast_one ? 0 : 1); | 
 | } | 
 |  | 
 | static int | 
 | disassembleRetIntern (uint32_t pc, uint32_t *retpop, sAddresses *seen, sAddresses *stack, | 
 | 		      int *hasret, int *atleast_one, const char *name, sImportname **ppimpname) | 
 | { | 
 |   size_t sz = 0; | 
 |   int code = 0,break_it = 0; | 
 |   volatile uint32_t tojmp = 0; | 
 |  | 
 |   while(1) | 
 |     { | 
 |       if (!push_addr (seen, pc)) | 
 |         return 0; | 
 |       sz = getMemonic (&code, pc, &tojmp, name, ppimpname) & 0xffffffff; | 
 |       if (!sz || code == c_ill) | 
 |         { | 
 |           PRDEBUG(" %s = 0x08%x ILL (%u) at least one==%d\n",name, | 
 | 		  (unsigned int) pc, (unsigned int) sz,atleast_one[0]); | 
 | #if ENABLE_DEBUG == 1 | 
 |       { | 
 |         unsigned char *ppc = (unsigned char *) map_va (pc); | 
 |         size_t i; | 
 |  | 
 |         fprintf (stderr, "%s(0x%x): ",name, (unsigned int) pc); | 
 |         for (i = 0;i < sz; i++) | 
 |           { | 
 |             fprintf (stderr, "%s0x%x", (i == 0 ? " ":","), ppc[i]); | 
 |           } | 
 |         fprintf (stderr, "\n"); | 
 |       } | 
 |       exit (0); | 
 | #endif | 
 |           break; | 
 |         } | 
 | #if ENABLE_DEBUG == 1 | 
 |       { | 
 |         unsigned char *ppc = (unsigned char *) map_va (pc); | 
 |         size_t i; | 
 |  | 
 |         fprintf (stderr, "%s(0x%x): ",name, (unsigned int) pc); | 
 |         for (i = 0;i < sz; i++) | 
 |           { | 
 |             fprintf (stderr, "%s0x%x", (i == 0 ? " ":","), ppc[i]); | 
 |           } | 
 |         fprintf (stderr, "\n"); | 
 |       } | 
 | #endif | 
 |       atleast_one[0] += 1; | 
 |       break_it = 0; | 
 |       pc += sz; | 
 |       switch(code) | 
 |         { | 
 |         case c_jmpnjb: case c_jmpnjv: | 
 |           pc = tojmp; | 
 |           break; | 
 |         case c_jxx: | 
 |           push_addr (stack, tojmp); | 
 |           break; | 
 |         case c_jmpfap: case c_int3: | 
 |           break_it = 1; | 
 |           break; | 
 |         case c_iret: case c_retf: case c_retn: | 
 |           *hasret = 1; | 
 |           if (assume_stdcall) | 
 |             *retpop = 0; | 
 |           return 1; | 
 |         case c_retflw: case c_retnlw: | 
 |           *hasret = 1; | 
 |           *retpop = tojmp; | 
 |           return 1; | 
 |         } | 
 |       if (break_it) | 
 |         break; | 
 |     } | 
 |  | 
 |   return 0; | 
 | } | 
 |  | 
 | static int opMap2[256] = { | 
 |   c_EG,c_EG,c_EG,c_EG,c_1,c_1,c_ill,c_ill, /* 0x00-0x07 */ | 
 |   c_1,c_1,c_ill,c_ill,c_ill,c_ill,c_ill,c_ill, /* 0x08-0x0f */ | 
 |   c_EG,c_EG,c_EG,c_EG,c_EG,c_EG,c_EG,c_EG, /* 0x10-0x17 */ | 
 |   c_EG,c_EG,c_EG,c_EG,c_EG,c_EG,c_EG,c_EG, /* 0x18-0x1f */ | 
 |   c_EG,c_EG,c_EG,c_EG,c_EG,c_ill,c_EG,c_ill, /* 0x20-0x27 */ | 
 |   c_EG,c_EG,c_EG,c_EG,c_EG,c_EG,c_EG,c_EG, /* 0x28-0x2f */ | 
 |   c_1,c_1,c_1,c_1,c_1,c_1,c_ill,c_1, /* 0x30-0x37 */ | 
 |   c_ill,c_ill,c_ill,c_ill,c_ill,c_ill,c_ill,c_ill, /* 0x38-0x3f */ | 
 |   c_EG,c_EG,c_EG,c_EG,c_EG,c_EG,c_EG,c_EG, /* 0x40-0x47 */ | 
 |   c_EG,c_EG,c_EG,c_EG,c_EG,c_EG,c_EG,c_EG, /* 0x48-0x4f */ | 
 |   c_EG,c_EG,c_EG,c_EG,c_EG,c_EG,c_EG,c_EG, /* 0x50-0x57 */ | 
 |   c_EG,c_EG,c_EG,c_EG,c_EG,c_EG,c_EG,c_EG, /* 0x58-0x5f */ | 
 |   c_EG,c_EG,c_EG,c_EG,c_EG,c_EG,c_EG,c_EG, /* 0x60-0x67 */ | 
 |   c_EG,c_EG,c_EG,c_EG,c_EG,c_EG,c_EG,c_EG, /* 0x68-0x6f */ | 
 |   c_EG,c_EG,c_EG,c_EG,c_EG,c_EG,c_EG,c_EG, /* 0x70-0x77 */ | 
 |   c_EG,c_EG,c_EG,c_EG,c_EG,c_EG,c_EG,c_EG, /* 0x78-0x7f */ | 
 |   c_jxxv,c_jxxv,c_jxxv,c_jxxv,c_jxxv,c_jxxv,c_jxxv,c_jxxv, /* 0x80-0x87 */ | 
 |   c_jxxv,c_jxxv,c_jxxv,c_jxxv,c_jxxv,c_jxxv,c_jxxv,c_jxxv, /* 0x88-0x8f */ | 
 |   c_EG,c_EG,c_EG,c_EG,c_EG,c_EG,c_EG,c_EG, /* 0x90-0x97 */ | 
 |   c_EG,c_EG,c_EG,c_EG,c_EG,c_EG,c_EG,c_EG, /* 0x98-0x9f */ | 
 |   c_1,c_1,c_1,c_EG,c_EGlb,c_EG,c_ill,c_ill, /* 0xa0-0xa7 */ | 
 |   c_1,c_1,c_1,c_EG,c_EGlb,c_EG,c_EG,c_EG, /* 0xa8-0xaf */ | 
 |   c_EG,c_EG,c_EG,c_EG,c_EG,c_EG,c_EG,c_EG, /* 0xb0-0xb7 */ | 
 |   c_EG,c_1,c_EGlb,c_EG, c_EG,c_EG,c_EG,c_EG, /* 0xb8-0xbf */ | 
 |   c_EG,c_EG,c_EGlb,c_EG,c_EGlb,c_EGlb,c_EGlb,c_EG, /* 0xc0-0xc7 */ | 
 |   c_1,c_1,c_1,c_1,c_1,c_1,c_1,c_1, /* 0xc8-0xcf */ | 
 |   c_EG,c_EG,c_EG,c_EG,c_EG,c_EG,c_EG,c_EG, /* 0xd0-0xd7 */ | 
 |   c_EG,c_EG,c_EG,c_EG,c_EG,c_EG,c_EG,c_EG, /* 0xd8-0xdf */ | 
 |   c_EG,c_EG,c_EG,c_EG,c_EG,c_EG,c_EG,c_EG, /* 0xe0-0xe7 */ | 
 |   c_EG,c_EG,c_EG,c_EG,c_EG,c_EG,c_EG,c_EG, /* 0xe8-0xef */ | 
 |   c_ill,c_EG,c_EG,c_EG,c_EG,c_EG,c_EG,c_EG, /* 0xf0-0xf7 */ | 
 |   c_EG,c_EG,c_EG,c_EG,c_EG,c_EG,c_EG,c_ill /* 0xf8-0xff */ | 
 | }; | 
 |  | 
 | static int opMap1[256] = { | 
 |   c_EG,c_EG,c_EG,c_EG,c_lb,c_lv,c_1,c_1, /* 0x00-0x07 */ | 
 |   c_EG,c_EG,c_EG,c_EG,c_lb,c_lv,c_1,c_0f, /* 0x08-0x0f */ | 
 |   c_EG,c_EG,c_EG,c_EG,c_lb,c_lv,c_1,c_1, /* 0x10-0x17 */ | 
 |   c_EG,c_EG,c_EG,c_EG,c_lb,c_lv,c_1,c_1, /* 0x18-0x1f */ | 
 |   c_EG,c_EG,c_EG,c_EG,c_lb,c_lv,c_1,c_1, /* 0x20-0x27 */ | 
 |   c_EG,c_EG,c_EG,c_EG,c_lb,c_lv,c_1,c_1, /* 0x28-0x2f */ | 
 |   c_EG,c_EG,c_EG,c_EG,c_lb,c_lv,c_1,c_1, /* 0x30-0x37 */ | 
 |   c_EG,c_EG,c_EG,c_EG,c_lb,c_lv,c_1,c_1, /* 0x38-0x3f */ | 
 |   c_1,c_1,c_1,c_1,c_1,c_1,c_1,c_1, /* 0x40-0x47 */ | 
 |   c_1,c_1,c_1,c_1,c_1,c_1,c_1,c_1, /* 0x48-0x4f */ | 
 |   c_1,c_1,c_1,c_1,c_1,c_1,c_1,c_1, /* 0x50-0x57 */ | 
 |   c_1,c_1,c_1,c_1,c_1,c_1,c_1,c_1, /* 0x58-0x5f */ | 
 |   c_1,c_1,c_EG,c_EG,c_1,c_1,c_op,c_ad, /* 0x60-0x67 */ | 
 |   c_lv,c_EGlv,c_lb,c_EGlb,c_1,c_1,c_1,c_1, /* 0x68-0x6f */ | 
 |   c_jxx,c_jxx,c_jxx,c_jxx,c_jxx,c_jxx,c_jxx,c_jxx, /* 0x70-0x77 */ | 
 |   c_jxx,c_jxx,c_jxx,c_jxx,c_jxx,c_jxx,c_jxx,c_jxx, /* 0x78-0x7f */ | 
 |   c_EGlb,c_EGlv,c_EGlb,c_EGlb,c_EG,c_EG,c_EG,c_EG, /* 0x80-0x87 */ | 
 |   c_EG,c_EG,c_EG,c_EG,c_EG,c_EG,c_EG,c_EG, /* 0x88-0x8f */ | 
 |   c_1,c_1,c_1,c_1,c_1,c_1,c_1,c_1, /* 0x90-0x97 */ | 
 |   c_1,c_1,c_callfar,c_1,c_1,c_1,c_1,c_1, /* 0x98-0x9f */ | 
 |   c_O,c_O,c_O,c_O,c_1,c_1,c_1,c_1, /* 0xa0-0xa7 */ | 
 |   c_lb,c_lv,c_1,c_1,c_1,c_1,c_1,c_1, /* 0xa8- 0xaf */ | 
 |   c_2,c_2,c_2,c_2,c_2,c_2,c_2,c_2, /* 0xb0-0xb7 */ | 
 |   c_lv,c_lv,c_lv,c_lv,c_lv,c_lv,c_lv,c_lv, /* 0xb8-0xbf */ | 
 |   c_EGlb,c_EGlb,c_retnlw,c_retn,c_EG,c_EG,c_EGlb,c_EGlv, /* 0xc0-0xc7 */ | 
 |   c_4,c_1,c_retflw,c_retf,c_int3,c_2,c_1,c_iret, /* 0xc8-0xcf */ | 
 |   c_EG,c_EG,c_EG,c_EG,c_2,c_2,c_1,c_1, /* 0xd0-0xd7 */ | 
 |   c_EG,c_EG,c_EG,c_EG,c_EG,c_EG,c_EG,c_EG, /* 0xd8-0xdf */ | 
 |   c_jxx,c_jxx,c_jxx,c_jxx,c_2,c_2,c_2,c_2, /* 0xe0-0xe7 */ | 
 |   c_calljv,c_jmpnjv,c_jmpfap,c_jmpnjb,c_1,c_1,c_1,c_1, /* 0xe8-0xef */ | 
 |   c_1,c_1,c_1,c_1, c_1,c_1,c_EGg3b,c_EGg3v, /* 0xf0-0xf7 */ | 
 |   c_1,c_1,c_1,c_1,c_1,c_1,c_g4,c_g4 /* 0xf8-0xff */ | 
 | }; | 
 |  | 
 | #if ENABLE_DEBUG == 1 | 
 |  | 
 | #define MAX_INSN_SAVE	20 | 
 |  | 
 | static void | 
 | enter_save_insn (unsigned char *s, unsigned char b) | 
 | { | 
 |   int i; | 
 |   for (i=0;i<MAX_INSN_SAVE-1;i++) | 
 |     s[i]=s[i+1]; | 
 |   s[MAX_INSN_SAVE-1]=b; | 
 | } | 
 |  | 
 | static void | 
 | print_save_insn (const char *name, unsigned char *s) | 
 | { | 
 |   int i; | 
 |    | 
 |   PRDEBUG("From %s: ",name); | 
 |   for (i=0;i<MAX_INSN_SAVE;i++) | 
 |   { | 
 |     PRDEBUG("%s0x%x",(i!=0 ? "," : ""), (unsigned int) s[i]); | 
 |   } | 
 | } | 
 | #endif | 
 |  | 
 | static size_t | 
 | getMemonic(int *aCode,uint32_t pc,volatile uint32_t *jmp_pc, __attribute__((unused)) const char *name, sImportname **ppimpname) | 
 | { | 
 | #if ENABLE_DEBUG == 1 | 
 |   static unsigned char lw[MAX_INSN_SAVE]; | 
 | #endif | 
 |   unsigned char *p; | 
 |   int addr_mode = 1; | 
 |   int oper_mode = 1; | 
 |   size_t sz = 0; | 
 |   unsigned char b; | 
 |   int tb1; | 
 |  | 
 |   for(;;) { | 
 |     p = (unsigned char *) map_va (pc + sz); | 
 |     if (!p) { *aCode=c_ill; return 0; } | 
 |     b = p[0]; | 
 |     if (b==0x26 || b==0x2e || b==0x36 || b==0x3e || b==0x64 || b==0x65) | 
 |       ++sz; | 
 |     else if (b==0x66) { oper_mode^=1; sz++; } | 
 |     else if (b==0x67) { addr_mode^=1; sz++; } | 
 |     else if (b==0xf2 || b==0xf3 || b==0xf0) sz++; | 
 |     else break; | 
 |   } | 
 |   sz++; | 
 |   tb1=opMap1[(unsigned int) b]; | 
 |    | 
 | redo_switch: | 
 | #if ENABLE_DEBUG == 1 | 
 |   if (tb1!=c_ill) { enter_save_insn(lw,b); } | 
 | #endif | 
 |   switch (tb1) { | 
 |   case c_ill: | 
 | #if ENABLE_DEBUG == 1 | 
 |     print_save_insn (name, lw); | 
 |     PRDEBUG(" 0x%x illegal ", (unsigned int) b); | 
 | #endif | 
 |     *aCode=c_ill; return 0; | 
 |   case c_4: sz++;/* fallthru */ | 
 |   case c_3: sz++;/* fallthru */ | 
 |   case c_lb: | 
 |   case c_2: sz++;/* fallthru */ | 
 |   case c_retn: case c_retf: | 
 |   case c_iret: case c_int3: | 
 |   case c_ad: case c_op: | 
 |   case c_1: *aCode=tb1; return sz; | 
 |   case c_lv: | 
 |     if (oper_mode) sz+=4; | 
 |     else sz+=2; | 
 |     *aCode=tb1; return sz; | 
 |   case c_O: case c_calljv: | 
 |     if (addr_mode) sz+=4; | 
 |     else sz+=2; | 
 |     *aCode=tb1; return sz; | 
 |   case c_EG: case c_EGlv: case c_EGlb: case c_g4: case c_EGg3v: case c_EGg3b: | 
 |     p = (unsigned char *) map_va (pc + sz); | 
 |     sz++; | 
 |     if (!p) { *aCode=c_ill; return 0; } | 
 |     b = p[0]; | 
 | #if ENABLE_DEBUG == 1 | 
 |     enter_save_insn(lw,b); | 
 | #endif | 
 |     if (addr_mode) { | 
 |       if((b&0xc0)!=0xc0 && (b&0x7)==4) | 
 |         { | 
 |           p = (unsigned char *) map_va (pc + sz); | 
 |           if (!p) { *aCode=c_ill; return 0; } | 
 | #if ENABLE_DEBUG == 1 | 
 | 	  enter_save_insn(lw,p[0]); | 
 | #endif | 
 |           b&=~0x7; b|=(p[0]&7); | 
 | 	  sz+=1; | 
 | 	} | 
 |       if((b&0xc0)==0 && (b&7)==5) | 
 |         { | 
 | 	  /* Here we check if for jmp instruction it points to an IAT entry.  */ | 
 | 	  if(tb1==c_g4 && ((b&0x38)==0x20 || (b&0x38)==0x28)) | 
 | 	    { | 
 | 	      uint32_t vaddr; | 
 | 	      sImportname *inss; | 
 | 	      vaddr = *((uint32_t *) map_va (pc + sz)); | 
 | 	      inss = imp32_findbyaddress (vaddr); | 
 | 	      if (inss) | 
 | 		*ppimpname = inss; | 
 | 	    } | 
 | 	  sz+=4; | 
 |         } | 
 |       else if((b&0xc0)==0x40) | 
 | 	sz+=1; | 
 |       else if((b&0xc0)==0x80) | 
 | 	sz+=4; | 
 |     } else { | 
 |       if((b&0xc0)==0) { | 
 | 	if((b&0x07)==6) sz+=2; | 
 |       } else if((b&0xc0)==0x40) | 
 | 	sz+=1; | 
 |       else if((b&0xc0)==0x80) | 
 | 	sz+=2; | 
 |     } | 
 |     if (tb1==c_EGlv) sz+=(oper_mode ? 4 : 2); | 
 |     else if(tb1==c_EGlb) sz++; | 
 |     else if(tb1==c_g4) { | 
 |       if ((b&0x38)==0x20 || (b&0x38)==0x28) | 
 | 	tb1=c_int3; | 
 |       else if((b&0x38)==0x38) | 
 |         tb1=c_ill; | 
 |     } else if (tb1==c_EGg3v || tb1==c_EGg3b) { | 
 |       switch (((b&0x38)>>3)) { | 
 |       case 1: | 
 |       case 0: sz+= (tb1==c_EGg3v ? (oper_mode ? 4 : 2) : 1); break; | 
 |       default: break; | 
 |       } | 
 |     } | 
 |     *aCode=tb1; return sz; | 
 |   case c_jxx: case c_jmpnjb: | 
 |     p = (unsigned char *) map_va (pc + sz); | 
 |     if (!p) { *aCode=c_ill; return 0; } | 
 |     b = p[0]; | 
 |     sz++; | 
 |     jmp_pc[0]=(uint32_t) pc + (uint32_t) sz; | 
 |     if ((b&0x80)!=0) | 
 |       jmp_pc[0] = jmp_pc[0] + (((uint32_t) b) | 0xffffff00); | 
 |     else | 
 |       jmp_pc[0] = jmp_pc[0] + (uint32_t) b; | 
 |     *aCode=tb1; return sz; | 
 |   case c_jmpnjv: | 
 |   case c_jxxv:  | 
 |     p = (unsigned char *) map_va (pc + sz); | 
 |     if (!p) { *aCode=c_ill; return 0; } | 
 |     if (oper_mode) { jmp_pc[0]=*((uint32_t *)p); sz+=4; } | 
 |     else { | 
 |       jmp_pc[0]=(uint32_t) *((uint16_t *)p); | 
 |       if ((jmp_pc[0]&0x8000)!=0) jmp_pc[0]|=0xffff0000; | 
 |       sz+=2; | 
 |     } | 
 |     jmp_pc[0]+=(uint32_t) pc+(uint32_t) sz; | 
 | #if ENABLE_DEBUG == 1 | 
 |     if ((jmp_pc[0]&0xff000000)!=0) { | 
 |       print_save_insn (name, lw); | 
 |       PRDEBUG(" 0x%x illegal ", (unsigned int) b); | 
 |       PRDEBUG("jmp(cond) 0x%x (sz=%x,pc=%x,off=%x) ", | 
 | 	      jmp_pc[0], (unsigned int) sz,(unsigned int) pc, | 
 |               (unsigned int) (jmp_pc[0]-(sz+pc))); | 
 |     } | 
 | #endif | 
 |     *aCode=(tb1==c_jxxv ? c_jxx : tb1); | 
 |     return sz; | 
 |   case c_0f: | 
 |     p = (unsigned char *) map_va (pc + sz); | 
 |     if (!p) { *aCode=c_ill; return 0; } | 
 |     b = p[0]; | 
 |     sz++; | 
 |     tb1=opMap2[b]; | 
 |     goto redo_switch; | 
 |   case c_jmpfap: | 
 |     sz+=4; if(oper_mode) sz+=2; | 
 |     *aCode=tb1; return sz; | 
 |   case c_callfar: | 
 |     sz+=4; if(oper_mode) sz+=2; | 
 |     *aCode=tb1; return sz; | 
 |   case c_retflw: case c_retnlw: | 
 |     p = (unsigned char *) map_va (pc + sz); | 
 |     if (!p) { *aCode=c_ill; return 0; } | 
 |     jmp_pc[0]=*((uint16_t*) p); | 
 |     sz+=2; | 
 |     *aCode=tb1; | 
 | #if ENABLE_DEBUG == 1 | 
 |     if (jmp_pc[0]>0x100 || jmp_pc[0]&3) { | 
 |       print_save_insn (name, lw); | 
 |       PRDEBUG(" 0x%x illegal ", (unsigned int) b); | 
 |       PRDEBUG("ret dw 0x%x (sz=%x) ", (unsigned int) jmp_pc[0], (unsigned int) sz); | 
 |     } | 
 | #endif | 
 |     return sz; | 
 |   default: | 
 |     PRDEBUG(" * opcode 0x%x (tbl=%d) unknown\n", (unsigned int) b, tb1); | 
 |     sz=0; *aCode=c_ill; break; | 
 |   } | 
 |   return sz; | 
 | } | 
 |  | 
 | static void | 
 | decode_mangle (FILE *fp, const char *n) | 
 | { | 
 | #ifdef HAVE_LIBMANGLE | 
 |   libmangle_gc_context_t *gc = libmangle_generate_gc (); | 
 |   libmangle_tokens_t ptok; | 
 | #endif | 
 |   if (!fp || !n || *n == 0) | 
 |     return; | 
 | #ifdef HAVE_LIBMANGLE | 
 |   ptok = libmangle_decode_ms_name (gc, n); | 
 |   if (ptok) | 
 |     { | 
 |       char *h = libmangle_sprint_decl (ptok); | 
 |       if (h) | 
 | 	{ | 
 | 	  fprintf (fp, "; %s\n", h); | 
 | 	  free (h); | 
 | 	} | 
 |     } | 
 |   libmangle_release_gc (gc); | 
 | #endif | 
 | } |