/* Copyright (c) 2009 mingw-w64 project Contributing authors: Kai Tietz, Jonathan Yong Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include #include #include #include #include "gendef.h" #define ENABLE_DEBUG 0 #if ENABLE_DEBUG == 1 #define PRDEBUG(ARG...) fprintf(stderr,ARG) #else #define PRDEBUG(ARG...) do { } while(0) #endif typedef enum eSPNA { SPNA_OPER_MINUSEQ=0,SPNA_OPER_PLUSEQ, SPNA_OPER_MULEQ,SPNA_OPER_OROR,SPNA_OPER_ANDAND,SPNA_OPER_OR,SPNA_OPER_XOR, SPNA_OPER_INV, SPNA_OPER_COMMA,SPNA_OPER_CAST, SPNA_OPER_SHR,SPNA_OPER_SHL,SPNA_OPER_SHREQ,SPNA_OPER_SHLEQ, SPNA_OPER_NOT,SPNA_OPER_EQEQ,SPNA_OPER_NOTEQ,SPNA_OPER_ARRAY, SPNA_OPER_RETURNTYPE,SPNA_OPER_POINTTO,SPNA_OPER_MUL, SPNA_OPER_PLUSPLUS,SPNA_OPER_MINUSMINUS,SPNA_OPER_MINUS,SPNA_OPER_PLUS, SPNA_OPER_AND,SPNA_OPER_POINTTOSTAR,SPNA_OPER_DIV,SPNA_OPER_MOD, SPNA_OPER_NEW_ARRAY,SPNA_OPER_DELETE_ARRAY, SPNA_CONSTRUCTOR,SPNA_DESTRUCTOR,SPNA_OPER_NEW,SPNA_OPER_DELETE, SPNA_OPER_EQ, SPNA_OPER_GREATEQ,SPNA_OPER_GREAT,SPNA_OPER_LESSEQ,SPNA_OPER_LESS, SPNA_OPER_DIVEQ,SPNA_OPER_MODEQ,SPNA_OPER_ANDEQ,SPNA_OPER_OREQ,SPNA_OPER_XOREQ, SPNA_RTTI_CLASS_HIERACHY_DESCRIPTOR,SPNA_RTTI_COMPLETE_OBJECT_LOCATOR, SPNA_LOCAL_VFTABLE,SPNA_LOCAL_VFTABLE_CONSTRUCTOR_CLOSURE, SPNA_PLACEMENT_DELETE_CLOSURE,SPNA_PLACEMENT_DELETE_ARRAY_CLOSURE, SPNA_VECTOR_DESTRUCTOR_ITER,SPNA_VECTOR_VBASE_CONSTRUCTOR_ITER, SPNA_VIRTUAL_DISPLACEMENT_MAP,SPNA_EH_VECTOR_CONSTRUCTOR_ITER, SPNA_EH_VECTOR_DESTRUCTOR_ITER,SPNA_EH_VECTOR_VBASE_CONSTRUCTOR_ITER, SPNA_COPY_CONSTRUCTOR_CLOSURE,SPNA_UDT_RETURNING, SPNA_RTTI_TYPE_DESCRIPTOR,SPNA_RTTI_BASE_CLASS_DESCRIPTOR, SPNA_RTTI_CLASS_ARRAY, SPNA_MANAGED_VECTOR_CONSTRUCTOR_ITER,SPNA_MANAGED_VECTOR_DESTRUCTOR_ITER, SPNA_EH_VECTOR_COPY_CONSTRUCTOR_ITER,SPNA_EH_VECTOR_VBASE_COPY_CONSTRUCTOR_ITER, SPNA_VFTABLE,SPNA_VBTABLE,SPNA_VCALL,SPNA_TYPEOF,SPNA_LOCAL_STATIC_GUARD, SPNA_STRING,SPNA_VBASE_DESTRUCTOR,SPNA_VECTOR_DELETING_DESTRUCTOR, SPNA_VECTOR_DEFAULT_CONSTRUCTOR_CLOSURE,SPNA_SCALAR_DELETEING_DESTRUCTOR, SPNA_VECTOR_CONSTRUCTOR_ITER, SPNA_UNKNOWN,SPNA_MAX } eSPNA; static const char *spna_names[SPNA_MAX] = { "-=","+=", "*=","||","&&","|","^", "~",",","operand ()", ">>","<<",">>=","<<=", "!","==","!=","operand []", "return type","->","operand *", "++","--","-","+", "&","->*","/","%", "new []","delete []", "()","~()","new","delete", "=", ">=",">","<=","<", "/=","%=","&=","|=","^=", "RTTI_CLASS_HIERACHY_DESCRIPTOR","RTTI_COMPLETE_OBJECT_LOCATOR", "LOCAL_VFTABLE","LOCAL_VFTABLE_CONSTRUCTOR_CLOSURE", "PLACEMENT_DELETE_CLOSURE","PLACEMENT_DELETE_ARRAY_CLOSURE", "VECTOR_DESTRUCTOR_ITER","VECTOR_VBASE_CONSTRUCTOR_ITER", "VIRTUAL_DISPLACEMENT_MAP","EH_VECTOR_CONSTRUCTOR_ITER", "EH_VECTOR_DESTRUCTOR_ITER","EH_VECTOR_VBASE_CONSTRUCTOR_ITER", "COPY_CONSTRUCTOR_CLOSURE","UDT_RETURNING", "RTTI_TYPE_DESCRIPTOR","RTTI_BASE_CLASS_DESCRIPTOR", "RTTI_CLASS_ARRAY", "MANAGED_VECTOR_CONSTRUCTOR_ITER","MANAGED_VECTOR_DESTRUCTOR_ITER", "EH_VECTOR_COPY_CONSTRUCTOR_ITER","EH_VECTOR_VBASE_COPY_CONSTRUCTOR_ITER", "VFTABLE","VBTABLE","VCALL","TYPEOF","LOCAL_STATIC_GUARD", "STRING","VBASE_DESTRUCTOR","VECTOR_DELETING_DESTRUCTOR", "VECTOR_DEFAULT_CONSTRUCTOR_CLOSURE","SCALAR_DELETEING_DESTRUCTOR", "VECTOR_CONSTRUCTOR_ITER", "unknown" }; void decode_mangle(const char *n); static int load_pep(void); static void do_pedef(void); static void do_pepdef(void); 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); static size_t getMemonic(int *aCode,uint32_t pc,volatile uint32_t *jmp_pc,const char *name); static void *map_va (uint32_t va); static int is_data (uint32_t va); static int is_reloc (uint32_t va); static int disassembleRetIntern(uint32_t pc,uint32_t *retpop,sAddresses *seen,sAddresses *stack,int *hasret,int *atleast_one,const char *name); 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; static int std_output = 0; static Gendefopts *chain_ptr = NULL; __attribute__((noreturn)) static void show_usage (void); void opt_chain (const char *); void opt_chain (const char *opts) { static Gendefopts *prev, *current; char *r1, *r2; if (!strncmp (opts, "-", 2)) { std_output = 1; return; } if (!strncmp (opts, "--help", 7)) { show_usage(); return; } 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; } 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" " --help Show this help.\n" ); 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, "\nReport bugs to \n"); exit (0); } int main(int argc,char **argv) { int i; Gendefopts *opt; if (argc < 2) { show_usage(); return 0; } for (i = 1; i < argc; i++) opt_chain (argv[i]); 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; } free(opt->fninput); free(opt->fnoutput); free(opt); opt = opt->next; } 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 == IMAGE_SIZEOF_NT_OPTIONAL32_HEADER && gPEDta->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) { gPEPDta = NULL; fprintf (stderr, " * [%s] Found PE image\n", fninput); } else if (gPEPDta->FileHeader.SizeOfOptionalHeader == IMAGE_SIZEOF_NT_OPTIONAL64_HEADER && 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, sz_rel, pos; unsigned char *p; PIMAGE_BASE_RELOCATION brel; if (gPEDta) { va_rel = gPEDta->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress; sz_rel = gPEDta->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size; } else { 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,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++) { if (va >= sec[i].VirtualAddress && va < (sec[i].VirtualAddress+sec[i].Misc.VirtualSize)) { 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 = gPEPDta->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress; uint32_t 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 = gPEDta->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress; uint32_t sz_exp = gPEDta->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size; do_export_read (va_exp, sz_exp, 0); } 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\n; written by Kai Tietz 2008\n;\n", fndllname); fprintf (fp,"LIBRARY \"%s\"\nEXPORTS\n",fndllname); while ((exp = gExp) != NULL) { gExp = exp->next; if (exp->name[0]==0) fprintf(fp,"ord_%u", (unsigned int) exp->ord); else fprintf(fp,"%s",exp->name); if (exp->name[0]=='?') { /* decode_mangle(exp->name); */ } if (exp->name[0]=='?' && exp->name[1]=='?') { if (!strncmp(exp->name,"??_7",4)) exp->beData=1; } if (!exp->beData && !exp->be64 && exp->func != 0) exp->beData = disassembleRet (exp->func, &exp->retpop,exp->name); if (exp->retpop != (uint32_t) -1) { if (exp->name[0]=='?') fprintf(fp," ; has WINAPI (@%u)", (unsigned int) exp->retpop); else fprintf(fp,"@%u", (unsigned int) exp->retpop); } if (exp->name[0]==0) fprintf(fp," @%u", (unsigned int) exp->ord); if (exp->beData) fprintf(fp," DATA"); 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; } /* exp->beData */ static int disassembleRet (uint32_t func, uint32_t *retpop, const char *name) { sAddresses *seen = init_addr (); sAddresses *stack = init_addr (); uint32_t pc; int hasret = 0; int atleast_one = 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)) break; } 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) { 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) & 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; 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>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; } int get_special_name(const char **np); void decode_mangle(const char *n) { if(!n || *n!='?') return; fprintf(stderr,"Decode ,%s'\n",n); n++; if(*n=='?') { int ret; n++; ret=get_special_name(&n); fprintf(stderr," %s (%s)\n",spna_names[ret],n); } } int get_special_name(const char **np) { int ret = SPNA_UNKNOWN; const char *n = *np; if(*n=='_' && n[1]=='_') { n+=2; switch(n[0]) { case 'A': ret=SPNA_MANAGED_VECTOR_CONSTRUCTOR_ITER; break; case 'B': ret=SPNA_MANAGED_VECTOR_DESTRUCTOR_ITER; break; case 'C': ret=SPNA_EH_VECTOR_COPY_CONSTRUCTOR_ITER; break; case 'D': ret=SPNA_EH_VECTOR_VBASE_COPY_CONSTRUCTOR_ITER; break; default: fprintf(stderr,"SPNA __%c is unknown\n",n[0]); break; } n+=1; } else if(n[0]=='_') { n+=1; switch(n[0]) { case '0': ret=SPNA_OPER_DIVEQ; break; case '1': ret=SPNA_OPER_MODEQ; break; case '2': ret=SPNA_OPER_SHREQ; break; case '3': ret=SPNA_OPER_SHLEQ; break; case '4': ret=SPNA_OPER_ANDEQ; break; case '5': ret=SPNA_OPER_OREQ; break; case '6': ret=SPNA_OPER_XOREQ; break; case '7': ret=SPNA_VFTABLE; break; case '8': ret=SPNA_VBTABLE; break; case '9': ret=SPNA_VCALL; break; case 'A': ret=SPNA_TYPEOF; break; case 'B': ret=SPNA_LOCAL_STATIC_GUARD; break; case 'C': ret=SPNA_STRING; break; case 'D': ret=SPNA_VBASE_DESTRUCTOR; break; case 'E': ret=SPNA_VECTOR_DELETING_DESTRUCTOR; break; case 'F': ret=SPNA_VECTOR_DEFAULT_CONSTRUCTOR_CLOSURE; break; case 'G': ret=SPNA_SCALAR_DELETEING_DESTRUCTOR; break; case 'H': ret=SPNA_VECTOR_CONSTRUCTOR_ITER; break; case 'I': ret=SPNA_VECTOR_DESTRUCTOR_ITER; break; case 'J': ret=SPNA_VECTOR_VBASE_CONSTRUCTOR_ITER; break; case 'K': ret=SPNA_VIRTUAL_DISPLACEMENT_MAP; break; case 'L': ret=SPNA_EH_VECTOR_CONSTRUCTOR_ITER; break; case 'M': ret=SPNA_EH_VECTOR_DESTRUCTOR_ITER; break; case 'N': ret=SPNA_EH_VECTOR_VBASE_CONSTRUCTOR_ITER; break; case 'O': ret=SPNA_COPY_CONSTRUCTOR_CLOSURE; break; case 'P': ret=SPNA_UDT_RETURNING; break; case 'R': n+=1; switch(n[0]) { case '0': ret=SPNA_RTTI_TYPE_DESCRIPTOR; break; case '1': ret=SPNA_RTTI_BASE_CLASS_DESCRIPTOR; break; case '2': ret=SPNA_RTTI_CLASS_ARRAY; break; case '3': ret=SPNA_RTTI_CLASS_HIERACHY_DESCRIPTOR; break; case '4': ret=SPNA_RTTI_COMPLETE_OBJECT_LOCATOR; break; default: fprintf(stderr,"SPNA _R%c is unknown\n",n[0]); break; } break; case 'S': ret=SPNA_LOCAL_VFTABLE; break; case 'T': ret=SPNA_LOCAL_VFTABLE_CONSTRUCTOR_CLOSURE; break; case 'U': ret=SPNA_OPER_NEW_ARRAY; break; case 'V': ret=SPNA_OPER_DELETE_ARRAY; break; case 'X': ret=SPNA_PLACEMENT_DELETE_CLOSURE; break; case 'Y': ret=SPNA_PLACEMENT_DELETE_ARRAY_CLOSURE; break; default: fprintf(stderr,"SPNA _%c unknown\n",n[0]); break; } n+=1; } else { switch(n[0]) { case '0': ret=SPNA_CONSTRUCTOR; break; case '1': ret=SPNA_DESTRUCTOR; break; case '2': ret=SPNA_OPER_NEW; break; case '3': ret=SPNA_OPER_DELETE; break; case '4': ret=SPNA_OPER_EQ; break; case '5': ret=SPNA_OPER_SHR; break; case '6': ret=SPNA_OPER_SHL; break; case '7': ret=SPNA_OPER_NOT; break; case '8': ret=SPNA_OPER_EQEQ; break; case '9': ret=SPNA_OPER_NOTEQ; break; case 'A': ret=SPNA_OPER_ARRAY; break; case 'B': ret=SPNA_OPER_RETURNTYPE; break; case 'C': ret=SPNA_OPER_POINTTO; break; case 'D': ret=SPNA_OPER_MUL; break; case 'E': ret=SPNA_OPER_PLUSPLUS; break; case 'F': ret=SPNA_OPER_MINUSMINUS; break; case 'G': ret=SPNA_OPER_MINUS; break; case 'H': ret=SPNA_OPER_PLUS; break; case 'I': ret=SPNA_OPER_AND; break; case 'J': ret=SPNA_OPER_POINTTOSTAR; break; case 'K': ret=SPNA_OPER_DIV; break; case 'L': ret=SPNA_OPER_MOD; break; case 'M': ret=SPNA_OPER_LESS; break; case 'N': ret=SPNA_OPER_LESSEQ; break; case 'O': ret=SPNA_OPER_GREAT; break; case 'P': ret=SPNA_OPER_GREATEQ; break; case 'Q': ret=SPNA_OPER_COMMA; break; case 'R': ret=SPNA_OPER_CAST; break; case 'S': ret=SPNA_OPER_INV; break; case 'T': ret=SPNA_OPER_XOR; break; case 'U': ret=SPNA_OPER_OR; break; case 'V': ret=SPNA_OPER_ANDAND; break; case 'W': ret=SPNA_OPER_OROR; break; case 'X': ret=SPNA_OPER_MULEQ; break; case 'Y': ret=SPNA_OPER_PLUSEQ; break; case 'Z': ret=SPNA_OPER_MINUSEQ; break; default: fprintf(stderr,"SPNA %c unknown\n",n[0]); break; } n+=1; } *np=n; return ret; }