X-Git-Url: https://notaz.gp2x.de/cgi-bin/gitweb.cgi?p=ia32rtools.git;a=blobdiff_plain;f=tools%2Fprotoparse.h;h=3d70d8658dfc1988e14a659bf851c38ffa6b7dd1;hp=2f558660a47fd97892c84c1247c6a757315b7867;hb=61e29183dd00fa64584fa8787008b21a1c70b8ce;hpb=a2c1d768e2fc1ab87bd2ac6e106c7400dd243185 diff --git a/tools/protoparse.h b/tools/protoparse.h index 2f55866..3d70d86 100644 --- a/tools/protoparse.h +++ b/tools/protoparse.h @@ -1,3 +1,10 @@ +/* + * ia32rtools + * (C) notaz, 2013,2014 + * + * This work is licensed under the terms of 3-clause BSD license. + * See COPYING file in the top-level directory. + */ struct parsed_proto; @@ -6,6 +13,8 @@ struct parsed_type { unsigned int is_array:1; unsigned int is_ptr:1; unsigned int is_struct:1; // split for args + unsigned int is_retreg:1; // register to return to caller + unsigned int is_va_list:1; }; struct parsed_proto_arg { @@ -27,10 +36,17 @@ struct parsed_proto { int argc_reg; unsigned int is_func:1; unsigned int is_stdcall:1; - unsigned int is_vararg:1; + unsigned int is_fastcall:1; + unsigned int is_vararg:1; // vararg func unsigned int is_fptr:1; unsigned int is_noreturn:1; + unsigned int is_unresolved:1; + unsigned int is_userstack:1; + unsigned int is_include:1; // not from top-level header + unsigned int is_osinc:1; // OS/system library func + unsigned int is_arg:1; // declared in some func arg unsigned int has_structarg:1; + unsigned int has_retreg:1; }; static const char *hdrfn; @@ -39,13 +55,17 @@ static int hdrfline = 0; static void pp_copy_arg(struct parsed_proto_arg *d, const struct parsed_proto_arg *s); -static int b_pp_c_handler(char *proto, const char *fname); +static int b_pp_c_handler(char *proto, const char *fname, + int is_include, int is_osinc); -static int do_protostrs(FILE *fhdr, const char *fname) +static int do_protostrs(FILE *fhdr, const char *fname, int is_include) { const char *finc_name; const char *hdrfn_saved; char protostr[256]; + char path[256]; + char fname_inc[256]; + int is_osinc; FILE *finc; int line = 0; int ret; @@ -54,6 +74,9 @@ static int do_protostrs(FILE *fhdr, const char *fname) hdrfn_saved = hdrfn; hdrfn = fname; + is_osinc = strstr(fname, "stdc.hlist") + || strstr(fname, "win32.hlist"); + while (fgets(protostr, sizeof(protostr), fhdr)) { line++; @@ -63,13 +86,22 @@ static int do_protostrs(FILE *fhdr, const char *fname) if (p != NULL) *p = 0; - finc = fopen(finc_name, "r"); + path[0] = 0; + p = strrchr(hdrfn_saved, '/'); + if (p) { + memcpy(path, hdrfn_saved, + p - hdrfn_saved + 1); + path[p - hdrfn_saved + 1] = 0; + } + snprintf(fname_inc, sizeof(fname_inc), "%s%s", + path, finc_name); + finc = fopen(fname_inc, "r"); if (finc == NULL) { printf("%s:%d: can't open '%s'\n", - fname, line, finc_name); + fname_inc, line, finc_name); continue; } - ret = do_protostrs(finc, finc_name); + ret = do_protostrs(finc, finc_name, 1); fclose(finc); if (ret < 0) break; @@ -86,7 +118,8 @@ static int do_protostrs(FILE *fhdr, const char *fname) hdrfline = line; - ret = b_pp_c_handler(protostr, hdrfn); + ret = b_pp_c_handler(protostr, hdrfn, is_include, + is_osinc); if (ret < 0) break; } @@ -99,14 +132,22 @@ static int do_protostrs(FILE *fhdr, const char *fname) return -1; } -static int get_regparm(char *dst, size_t dlen, char *p) +static int get_regparm(char *dst, size_t dlen, char *p, int *retreg) { - int i, o; + int i = 0, o; + + *retreg = 0; if (*p != '<') return 0; - for (o = 0, i = 1; o < dlen; i++) { + i++; + if (p[i] == '*') { + *retreg = 1; + i++; + } + + for (o = 0; o < dlen; i++) { if (p[i] == 0) return 0; if (p[i] == '>') @@ -125,31 +166,48 @@ static const char *known_type_mod[] = { "struct", "enum", "CONST", + "volatile", }; static const char *known_ptr_types[] = { + "FARPROC", + "WNDPROC", + "LINECALLBACK", "HACCEL", "HANDLE", "HBITMAP", + "HCALL", "HCURSOR", "HDC", "HFONT", "HGDIOBJ", "HGLOBAL", + "HICON", "HINSTANCE", + "HIMC", // DWORD in mingw, ptr in wine.. + "HLINE", + "HLINEAPP", + "HLOCAL", "HMODULE", + "HPALETTE", "HRGN", "HRSRC", "HKEY", "HMENU", + "HWAVEOUT", "HWND", + "PBYTE", "PCRITICAL_SECTION", "PDWORD", + "PFILETIME", + "PLARGE_INTEGER", "PHKEY", "PLONG", "PMEMORY_BASIC_INFORMATION", + "PUINT", "PVOID", "PCVOID", + "PWORD", "DLGPROC", "TIMERPROC", "WNDENUMPROC", @@ -238,6 +296,8 @@ static int check_type(const char *name, struct parsed_type *type) ret = n1 - name; type->name = strndup(name, ret); + if (IS(type->name, "__VALIST") || IS(type->name, "va_list")) + type->is_va_list = 1; if (IS(type->name, "VOID")) memcpy(type->name, "void", 4); @@ -277,6 +337,7 @@ static int parse_protostr(char *protostr, struct parsed_proto *pp) char regparm[16]; char buf[256]; char cconv[32]; + int is_retreg; int xarg = 0; char *p, *p1; int i, l; @@ -314,6 +375,11 @@ static int parse_protostr(char *protostr, struct parsed_proto *pp) } p = sskip(p + ret); + if (!strncmp(p, "noreturn ", 9)) { + pp->is_noreturn = 1; + p = sskip(p + 9); + } + if (!strchr(p, ')')) { p = next_idt(buf, sizeof(buf), p); p = sskip(p); @@ -350,14 +416,20 @@ static int parse_protostr(char *protostr, struct parsed_proto *pp) pp->is_stdcall = 0; else if (IS(cconv, "__stdcall")) pp->is_stdcall = 1; - else if (IS(cconv, "__fastcall")) - pp->is_stdcall = 1; + else if (IS(cconv, "__fastcall")) { + pp->is_fastcall = 1; + pp->is_stdcall = 1; // sort of.. + } else if (IS(cconv, "__thiscall")) pp->is_stdcall = 1; else if (IS(cconv, "__userpurge")) pp->is_stdcall = 1; // IDA else if (IS(cconv, "__usercall")) pp->is_stdcall = 0; // IDA + else if (IS(cconv, "__userstack")) { + pp->is_stdcall = 0; // custom + pp->is_userstack = 1; + } else if (IS(cconv, "WINAPI")) pp->is_stdcall = 1; else { @@ -388,7 +460,7 @@ static int parse_protostr(char *protostr, struct parsed_proto *pp) } strcpy(pp->name, buf); - ret = get_regparm(regparm, sizeof(regparm), p); + ret = get_regparm(regparm, sizeof(regparm), p, &is_retreg); if (ret > 0) { if (!IS(regparm, "eax") && !IS(regparm, "ax") && !IS(regparm, "al") && !IS(regparm, "edx:eax")) @@ -482,6 +554,10 @@ static int parse_protostr(char *protostr, struct parsed_proto *pp) hdrfn, hdrfline, p1 - protostr); return -1; } + arg->fptr->is_arg = 1; + // we don't use actual names right now.. + snprintf(arg->fptr->name, + sizeof(arg->fptr->name), "a%d", xarg); // we'll treat it as void * for non-calls arg->type.name = strdup("void *"); arg->type.is_ptr = 1; @@ -500,12 +576,24 @@ static int parse_protostr(char *protostr, struct parsed_proto *pp) #endif arg->reg = NULL; - ret = get_regparm(regparm, sizeof(regparm), p); + ret = get_regparm(regparm, sizeof(regparm), p, &is_retreg); if (ret > 0) { p += ret; p = sskip(p); arg->reg = strdup(map_reg(regparm)); + arg->type.is_retreg = is_retreg; + pp->has_retreg |= is_retreg; + } + + if (strstr(arg->type.name, "int64") + || IS(arg->type.name, "double")) + { + // hack.. + free(arg->type.name); + arg->type.name = strdup("int"); + pp_copy_arg(&pp->arg[xarg], arg); + xarg++; } ret = check_struct_arg(arg); @@ -537,11 +625,6 @@ static int parse_protostr(char *protostr, struct parsed_proto *pp) pp->arg[1].reg = strdup("edx"); } - if (pp->is_vararg && pp->is_stdcall) { - printf("%s:%d: vararg stdcall?\n", hdrfn, hdrfline); - return -1; - } - pp->argc = xarg; for (i = 0; i < pp->argc; i++) { @@ -551,6 +634,23 @@ static int parse_protostr(char *protostr, struct parsed_proto *pp) pp->argc_reg++; } + if (pp->argc == 1 && pp->arg[0].reg != NULL + && IS(pp->arg[0].reg, "ecx")) + { + pp->is_fastcall = 1; + } + else if (pp->argc_reg == 2 + && pp->arg[0].reg != NULL && IS(pp->arg[0].reg, "ecx") + && pp->arg[1].reg != NULL && IS(pp->arg[1].reg, "edx")) + { + pp->is_fastcall = 1; + } + + if (pp->is_vararg && (pp->is_stdcall || pp->is_fastcall)) { + printf("%s:%d: vararg %s?\n", hdrfn, hdrfline, cconv); + return -1; + } + return p - protostr; } @@ -564,7 +664,8 @@ static struct parsed_proto *pp_cache; static int pp_cache_size; static int pp_cache_alloc; -static int b_pp_c_handler(char *proto, const char *fname) +static int b_pp_c_handler(char *proto, const char *fname, + int is_include, int is_osinc) { int ret; @@ -582,27 +683,34 @@ static int b_pp_c_handler(char *proto, const char *fname) if (ret < 0) return -1; + pp_cache[pp_cache_size].is_include = is_include; + pp_cache[pp_cache_size].is_osinc = is_osinc; pp_cache_size++; return 0; } static void build_pp_cache(FILE *fhdr) { + long pos; int ret; + pos = ftell(fhdr); rewind(fhdr); - ret = do_protostrs(fhdr, hdrfn); + ret = do_protostrs(fhdr, hdrfn, 0); if (ret < 0) exit(1); qsort(pp_cache, pp_cache_size, sizeof(pp_cache[0]), pp_name_cmp); + fseek(fhdr, pos, SEEK_SET); } -static const struct parsed_proto *proto_parse(FILE *fhdr, const char *sym) +static const struct parsed_proto *proto_parse(FILE *fhdr, const char *sym, + int quiet) { const struct parsed_proto *pp_ret; struct parsed_proto pp_search; + char *p; if (pp_cache == NULL) build_pp_cache(fhdr); @@ -611,9 +719,13 @@ static const struct parsed_proto *proto_parse(FILE *fhdr, const char *sym) sym++; strcpy(pp_search.name, sym); + p = strchr(pp_search.name, '@'); + if (p != NULL) + *p = 0; + pp_ret = bsearch(&pp_search, pp_cache, pp_cache_size, sizeof(pp_cache[0]), pp_name_cmp); - if (pp_ret == NULL) + if (pp_ret == NULL && !quiet) printf("%s: sym '%s' is missing\n", hdrfn, sym); return pp_ret; @@ -657,6 +769,52 @@ struct parsed_proto *proto_clone(const struct parsed_proto *pp_c) return pp; } + +static inline int pp_cmp_func(const struct parsed_proto *pp1, + const struct parsed_proto *pp2) +{ + int i; + + if (pp1->argc != pp2->argc || pp1->argc_reg != pp2->argc_reg) + return 1; + else { + for (i = 0; i < pp1->argc; i++) { + if ((pp1->arg[i].reg != NULL) != (pp2->arg[i].reg != NULL)) + return 1; + + if ((pp1->arg[i].reg != NULL) + && !IS(pp1->arg[i].reg, pp2->arg[i].reg)) + { + return 1; + } + } + } + + return 0; +} + +static inline void pp_print(char *buf, size_t buf_size, + const struct parsed_proto *pp) +{ + size_t l; + int i; + + snprintf(buf, buf_size, "%s %s(", pp->ret_type.name, pp->name); + l = strlen(buf); + + for (i = 0; i < pp->argc_reg; i++) { + snprintf(buf + l, buf_size - l, "%s%s", + i == 0 ? "" : ", ", pp->arg[i].reg); + l = strlen(buf); + } + if (pp->argc_stack > 0) { + snprintf(buf + l, buf_size - l, "%s{%d stack}", + i == 0 ? "" : ", ", pp->argc_stack); + l = strlen(buf); + } + snprintf(buf + l, buf_size - l, ")"); +} + static inline void proto_release(struct parsed_proto *pp) { int i;