From bd96f6564765a72d647fbf31de3120ad7f363653 Mon Sep 17 00:00:00 2001 From: notaz Date: Tue, 31 Dec 2013 01:54:22 +0200 Subject: [PATCH] header pre-parsing --- tools/mkbridge.c | 20 +++--- tools/protoparse.h | 171 +++++++++++++++++++++++++++++++++++---------- tools/translate.c | 94 +++++++++++++------------ win32.hlist | 2 - 4 files changed, 192 insertions(+), 95 deletions(-) diff --git a/tools/mkbridge.c b/tools/mkbridge.c index 5bcd84a..3b3f4ce 100644 --- a/tools/mkbridge.c +++ b/tools/mkbridge.c @@ -23,7 +23,7 @@ static int is_x86_reg_saved(const char *reg) return !nosave; } -static void out_toasm_x86(FILE *f, char *sym, struct parsed_proto *pp) +static void out_toasm_x86(FILE *f, char *sym, const struct parsed_proto *pp) { int must_save = 0; int sarg_ofs = 1; // stack offset to args, in DWORDs @@ -103,7 +103,7 @@ static void out_toasm_x86(FILE *f, char *sym, struct parsed_proto *pp) fprintf(f, "\tret\n\n"); } -static void out_fromasm_x86(FILE *f, char *sym, struct parsed_proto *pp) +static void out_fromasm_x86(FILE *f, char *sym, const struct parsed_proto *pp) { int sarg_ofs = 1; // stack offset to args, in DWORDs int argc_repush; @@ -166,7 +166,7 @@ static void out_fromasm_x86(FILE *f, char *sym, struct parsed_proto *pp) int main(int argc, char *argv[]) { FILE *fout, *fsyms_to, *fsyms_from, *fhdr; - struct parsed_proto pp; + const struct parsed_proto *pp; char line[256]; char sym[256]; int ret; @@ -199,12 +199,11 @@ int main(int argc, char *argv[]) if (sym[0] == 0 || sym[0] == ';' || sym[0] == '#') continue; - ret = proto_parse(fhdr, sym, &pp); - if (ret) + pp = proto_parse(fhdr, sym); + if (pp == NULL) goto out; - out_toasm_x86(fout, sym, &pp); - proto_release(&pp); + out_toasm_x86(fout, sym, pp); } fprintf(fout, "# from asm\n\n"); @@ -215,12 +214,11 @@ int main(int argc, char *argv[]) if (sym[0] == 0 || sym[0] == ';' || sym[0] == '#') continue; - ret = proto_parse(fhdr, sym, &pp); - if (ret) + pp = proto_parse(fhdr, sym); + if (pp == NULL) goto out; - out_fromasm_x86(fout, sym, &pp); - proto_release(&pp); + out_fromasm_x86(fout, sym, pp); } ret = 0; diff --git a/tools/protoparse.h b/tools/protoparse.h index 267ef73..673fcb7 100644 --- a/tools/protoparse.h +++ b/tools/protoparse.h @@ -34,28 +34,26 @@ struct parsed_proto { static const char *hdrfn; static int hdrfline = 0; -static int find_protostr(char *dst, size_t dlen, FILE *fhdr, - const char *fname, const char *sym_) +static int b_pp_c_handler(char *proto, const char *fname); + +static int do_protostrs(FILE *fhdr, const char *fname) { - const char *sym = sym_; const char *finc_name; + const char *hdrfn_saved; + char protostr[256]; FILE *finc; - int symlen; int line = 0; int ret; char *p; - if (sym[0] == '_' && strncmp(fname, "stdc", 4) == 0) - sym++; - symlen = strlen(sym); + hdrfn_saved = hdrfn; + hdrfn = fname; - rewind(fhdr); - - while (fgets(dst, dlen, fhdr)) + while (fgets(protostr, sizeof(protostr), fhdr)) { line++; - if (strncmp(dst, "//#include ", 11) == 0) { - finc_name = dst + 11; + if (strncmp(protostr, "//#include ", 11) == 0) { + finc_name = protostr + 11; p = strpbrk(finc_name, "\r\n "); if (p != NULL) *p = 0; @@ -66,32 +64,34 @@ static int find_protostr(char *dst, size_t dlen, FILE *fhdr, fname, line, finc_name); continue; } - ret = find_protostr(dst, dlen, finc, - finc_name, sym_); + ret = do_protostrs(finc, finc_name); fclose(finc); - if (ret == 0) + if (ret < 0) break; continue; } - if (strncmp(sskip(dst), "//", 2) == 0) + if (strncmp(sskip(protostr), "//", 2) == 0) + continue; + + p = protostr + strlen(protostr); + for (p--; p >= protostr && my_isblank(*p); --p) + *p = 0; + if (p < protostr) continue; - p = strstr(dst, sym); - if (p != NULL && p > dst - && (my_isblank(p[-1]) || my_issep(p[-1])) - && (my_isblank(p[symlen]) || my_issep(p[symlen]))) + hdrfline = line; + + ret = b_pp_c_handler(protostr, hdrfn); + if (ret < 0) break; } - hdrfline = line; - if (feof(fhdr)) - return -1; + hdrfn = hdrfn_saved; - p = dst + strlen(dst); - for (p--; p > dst && my_isblank(*p); --p) - *p = 0; + if (feof(fhdr)) + return 0; - return 0; + return -1; } static int get_regparm(char *dst, size_t dlen, char *p) @@ -177,6 +177,8 @@ static const char *skip_type_mod(const char *n) len = strlen(known_type_mod[i]); if (strncmp(n, known_type_mod[i], len) != 0) continue; + if (!my_isblank(n[len])) + continue; n += len; while (my_isblank(*n)) @@ -347,7 +349,11 @@ static int parse_protostr(char *protostr, struct parsed_proto *pp) hdrfn, hdrfline, (p - protostr) + 1); return -1; } - p = sskip(p + 1); + p++; + // XXX: skipping extra asterisks, for now + while (*p == '*') + p++; + p = sskip(p); } p = next_idt(buf, sizeof(buf), p); @@ -373,6 +379,17 @@ static int parse_protostr(char *protostr, struct parsed_proto *pp) } if (pp->is_fptr) { + if (*p == '[') { + // not really ret_type is array, but ohwell + pp->ret_type.is_array = 1; + p = strchr(p + 1, ']'); + if (p == NULL) { + printf("%s:%d:%zd: ']' expected\n", + hdrfn, hdrfline, (p - protostr) + 1); + return -1; + } + p = sskip(p + 1); + } if (*p != ')') { printf("%s:%d:%zd: ')' expected\n", hdrfn, hdrfline, (p - protostr) + 1); @@ -496,23 +513,104 @@ static int parse_protostr(char *protostr, struct parsed_proto *pp) return p - protostr; } -static int proto_parse(FILE *fhdr, const char *sym, struct parsed_proto *pp) +static int pp_name_cmp(const void *p1, const void *p2) +{ + const struct parsed_proto *pp1 = p1, *pp2 = p2; + return strcmp(pp1->name, pp2->name); +} + +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) +{ + int ret; + + if (pp_cache_size >= pp_cache_alloc) { + pp_cache_alloc = pp_cache_alloc * 2 + 64; + pp_cache = realloc(pp_cache, pp_cache_alloc + * sizeof(pp_cache[0])); + my_assert_not(pp_cache, NULL); + memset(pp_cache + pp_cache_size, 0, + (pp_cache_alloc - pp_cache_size) + * sizeof(pp_cache[0])); + } + + ret = parse_protostr(proto, &pp_cache[pp_cache_size]); + if (ret < 0) + return -1; + + pp_cache_size++; + return 0; +} + +static void build_pp_cache(FILE *fhdr) { - char protostr[256]; int ret; - memset(pp, 0, sizeof(*pp)); + rewind(fhdr); + + ret = do_protostrs(fhdr, hdrfn); + if (ret < 0) + exit(1); + + qsort(pp_cache, pp_cache_size, sizeof(pp_cache[0]), pp_name_cmp); +} + +static const struct parsed_proto *proto_parse(FILE *fhdr, const char *sym) +{ + const struct parsed_proto *pp_ret; + struct parsed_proto pp_search; + + if (pp_cache == NULL) + build_pp_cache(fhdr); + + if (sym[0] == '_') // && strncmp(fname, "stdc", 4) == 0) + sym++; - ret = find_protostr(protostr, sizeof(protostr), fhdr, hdrfn, sym); - if (ret != 0) { + strcpy(pp_search.name, sym); + pp_ret = bsearch(&pp_search, pp_cache, pp_cache_size, + sizeof(pp_cache[0]), pp_name_cmp); + if (pp_ret == NULL) printf("%s: sym '%s' is missing\n", hdrfn, sym); - return ret; + + return pp_ret; +} + +struct parsed_proto *proto_clone(const struct parsed_proto *pp_c) +{ + struct parsed_proto *pp; + int i; + + pp = malloc(sizeof(*pp)); + my_assert_not(pp, NULL); + memcpy(pp, pp_c, sizeof(*pp)); // lazy.. + + // do the actual deep copy.. + for (i = 0; i < pp_c->argc; i++) { + if (pp_c->arg[i].reg != NULL) { + pp->arg[i].reg = strdup(pp_c->arg[i].reg); + my_assert_not(pp->arg[i].reg, NULL); + } + if (pp_c->arg[i].type.name != NULL) { + pp->arg[i].type.name = strdup(pp_c->arg[i].type.name); + my_assert_not(pp->arg[i].type.name, NULL); + } + if (pp_c->arg[i].fptr != NULL) { + pp->arg[i].fptr = malloc(sizeof(*pp->arg[i].fptr)); + my_assert_not(pp->arg[i].fptr, NULL); + memcpy(pp->arg[i].fptr, pp_c->arg[i].fptr, + sizeof(*pp->arg[i].fptr)); + } } + if (pp_c->ret_type.name != NULL) + pp->ret_type.name = strdup(pp_c->ret_type.name); - return parse_protostr(protostr, pp) < 0 ? -1 : 0; + return pp; } -static void proto_release(struct parsed_proto *pp) +static inline void proto_release(struct parsed_proto *pp) { int i; @@ -526,4 +624,5 @@ static void proto_release(struct parsed_proto *pp) } if (pp->ret_type.name != NULL) free(pp->ret_type.name); + free(pp); } diff --git a/tools/translate.c b/tools/translate.c index 7c7390e..7cbf8b7 100644 --- a/tools/translate.c +++ b/tools/translate.c @@ -188,7 +188,7 @@ static struct parsed_equ *g_eqs; static int g_eqcnt; static char g_labels[MAX_OPS][32]; static struct label_ref g_label_refs[MAX_OPS]; -static struct parsed_proto g_func_pp; +static const struct parsed_proto *g_func_pp; static struct parsed_data *g_func_pd; static int g_func_pd_cnt; static char g_func[256]; @@ -469,6 +469,7 @@ static int guess_lmod_from_c_type(enum opr_lenmod *lmod, { static const char *dword_types[] = { "int", "_DWORD", "DWORD", "HANDLE", "HWND", "HMODULE", + "WPARAM", "UINT", }; static const char *word_types[] = { "uint16_t", "int16_t", @@ -541,7 +542,7 @@ static int parse_operand(struct parsed_opr *opr, int *regmask, int *regmask_indirect, char words[16][256], int wordc, int w, unsigned int op_flags) { - struct parsed_proto pp; + const struct parsed_proto *pp; enum opr_lenmod tmplmod; unsigned long number; int ret, len; @@ -672,16 +673,16 @@ static int parse_operand(struct parsed_opr *opr, // most likely var in data segment opr->type = OPT_LABEL; - ret = proto_parse(g_fhdr, opr->name, &pp); - if (ret == 0) { - if (pp.is_fptr) { + pp = proto_parse(g_fhdr, opr->name); + if (pp != NULL) { + if (pp->is_fptr) { opr->lmod = OPLM_DWORD; opr->is_ptr = 1; } else { - if (!guess_lmod_from_c_type(&tmplmod, &pp.type)) + if (!guess_lmod_from_c_type(&tmplmod, &pp->type)) anote("unhandled C type '%s' for '%s'\n", - pp.type.name, opr->name); + pp->type.name, opr->name); if (opr->lmod == OPLM_UNSPEC) opr->lmod = tmplmod; @@ -691,10 +692,9 @@ static int parse_operand(struct parsed_opr *opr, opr->size_lt = 1; } } - opr->is_ptr = pp.type.is_ptr; - opr->is_array = pp.type.is_array; + opr->is_ptr = pp->type.is_ptr; + opr->is_array = pp->type.is_array; } - proto_release(&pp); if (opr->lmod == OPLM_UNSPEC) guess_lmod_from_name(opr); @@ -1215,9 +1215,11 @@ static void stack_frame_access(struct parsed_op *po, if (offset > stack_ra) { arg_i = (offset - stack_ra - 4) / 4; - if (arg_i < 0 || arg_i >= g_func_pp.argc_stack) + if (arg_i < 0 || arg_i >= g_func_pp->argc_stack) { - if (g_func_pp.is_vararg && arg_i == g_func_pp.argc_stack && is_lea) { + if (g_func_pp->is_vararg + && arg_i == g_func_pp->argc_stack && is_lea) + { // should be va_list if (cast[0] == 0) cast = "(u32)"; @@ -1230,17 +1232,17 @@ static void stack_frame_access(struct parsed_op *po, if (ofs_reg[0] != 0) ferr(po, "offset reg on arg access?\n"); - for (i = arg_s = 0; i < g_func_pp.argc; i++) { - if (g_func_pp.arg[i].reg != NULL) + for (i = arg_s = 0; i < g_func_pp->argc; i++) { + if (g_func_pp->arg[i].reg != NULL) continue; if (arg_s == arg_i) break; arg_s++; } - if (i == g_func_pp.argc) + if (i == g_func_pp->argc) ferr(po, "arg %d not in prototype?\n", arg_i); - popr->is_ptr = g_func_pp.arg[i].type.is_ptr; + popr->is_ptr = g_func_pp->arg[i].type.is_ptr; switch (popr->lmod) { @@ -1290,10 +1292,10 @@ static void stack_frame_access(struct parsed_op *po, } // common problem - guess_lmod_from_c_type(&tmp_lmod, &g_func_pp.arg[i].type); + guess_lmod_from_c_type(&tmp_lmod, &g_func_pp->arg[i].type); if ((offset & 3) && tmp_lmod != OPLM_DWORD) ferr(po, "bp_arg arg/w offset %d and type '%s'\n", - offset, g_func_pp.arg[i].type.name); + offset, g_func_pp->arg[i].type.name); } else { @@ -2155,6 +2157,7 @@ static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt) struct parsed_op *po, *delayed_flag_op = NULL, *tmp_op; struct parsed_opr *last_arith_dst = NULL; char buf1[256], buf2[256], buf3[256], cast[64]; + const struct parsed_proto *pp_c; struct parsed_proto *pp, *pp_tmp; struct parsed_data *pd; const char *tmpname; @@ -2179,20 +2182,20 @@ static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt) g_bp_frame = g_sp_frame = g_stack_fsz = 0; - ret = proto_parse(fhdr, funcn, &g_func_pp); - if (ret) + g_func_pp = proto_parse(fhdr, funcn); + if (g_func_pp == NULL) ferr(ops, "proto_parse failed for '%s'\n", funcn); - fprintf(fout, "%s ", g_func_pp.ret_type.name); + fprintf(fout, "%s ", g_func_pp->ret_type.name); if (g_ida_func_attr & IDAFA_NORETURN) fprintf(fout, "noreturn "); fprintf(fout, "%s(", funcn); - for (i = 0; i < g_func_pp.argc; i++) { + for (i = 0; i < g_func_pp->argc; i++) { if (i > 0) fprintf(fout, ", "); - fprintf(fout, "%s a%d", g_func_pp.arg[i].type.name, i + 1); + fprintf(fout, "%s a%d", g_func_pp->arg[i].type.name, i + 1); } - if (g_func_pp.is_vararg) { + if (g_func_pp->is_vararg) { if (i > 0) fprintf(fout, ", "); fprintf(fout, "..."); @@ -2403,9 +2406,10 @@ static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt) pp->arg[arg].type.name = strdup("int"); } else { - ret = proto_parse(fhdr, tmpname, pp); - if (ret) + pp_c = proto_parse(fhdr, tmpname); + if (pp_c == NULL) ferr(po, "proto_parse failed for call '%s'\n", tmpname); + pp = proto_clone(pp_c); } // look for and make use of esp adjust @@ -2596,27 +2600,27 @@ static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt) fprintf(fout, " union { u32 d[%d]; u16 w[%d]; u8 b[%d]; } sf;\n", (g_stack_fsz + 3) / 4, (g_stack_fsz + 1) / 2, g_stack_fsz); - if (g_func_pp.is_vararg) + if (g_func_pp->is_vararg) fprintf(fout, " va_list ap;\n"); // declare arg-registers - for (i = 0; i < g_func_pp.argc; i++) { - if (g_func_pp.arg[i].reg != NULL) { + for (i = 0; i < g_func_pp->argc; i++) { + if (g_func_pp->arg[i].reg != NULL) { reg = char_array_i(regs_r32, - ARRAY_SIZE(regs_r32), g_func_pp.arg[i].reg); + ARRAY_SIZE(regs_r32), g_func_pp->arg[i].reg); if (reg < 0) - ferr(ops, "arg '%s' is not a reg?\n", g_func_pp.arg[i].reg); + ferr(ops, "arg '%s' is not a reg?\n", g_func_pp->arg[i].reg); regmask_arg |= 1 << reg; fprintf(fout, " u32 %s = (u32)a%d;\n", - g_func_pp.arg[i].reg, i + 1); + g_func_pp->arg[i].reg, i + 1); had_decl = 1; } } // declare other regs - special case for eax if (!((regmask | regmask_arg) & 1) - && !IS(g_func_pp.ret_type.name, "void")) + && !IS(g_func_pp->ret_type.name, "void")) { fprintf(fout, " u32 eax = 0;\n"); had_decl = 1; @@ -2670,10 +2674,10 @@ static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt) if (had_decl) fprintf(fout, "\n"); - if (g_func_pp.is_vararg) { - if (g_func_pp.argc_stack == 0) + if (g_func_pp->is_vararg) { + if (g_func_pp->argc_stack == 0) ferr(ops, "vararg func without stack args?\n"); - fprintf(fout, " va_start(ap, a%d);\n", g_func_pp.argc); + fprintf(fout, " va_start(ap, a%d);\n", g_func_pp->argc); } // output ops @@ -3088,8 +3092,8 @@ static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt) else if (!IS(pp->ret_type.name, "void")) { if (po->flags & OPF_TAIL) { fprintf(fout, "return "); - if (g_func_pp.ret_type.is_ptr != pp->ret_type.is_ptr) - fprintf(fout, "(%s)", g_func_pp.ret_type.name); + if (g_func_pp->ret_type.is_ptr != pp->ret_type.is_ptr) + fprintf(fout, "(%s)", g_func_pp->ret_type.name); } else { fprintf(fout, "eax = "); @@ -3155,16 +3159,16 @@ static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt) break; case OP_RET: - if (g_func_pp.is_vararg) + if (g_func_pp->is_vararg) fprintf(fout, " va_end(ap);\n"); - if (IS(g_func_pp.ret_type.name, "void")) { + if (IS(g_func_pp->ret_type.name, "void")) { if (i != opcnt - 1 || label_pending) fprintf(fout, " return;"); } - else if (g_func_pp.ret_type.is_ptr) { + else if (g_func_pp->ret_type.is_ptr) { fprintf(fout, " return (%s)eax;", - g_func_pp.ret_type.name); + g_func_pp->ret_type.name); } else fprintf(fout, " return eax;"); @@ -3259,13 +3263,11 @@ static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt) if (ops[i].op == OP_CALL) { pp = ops[i].datap; - if (pp) { + if (pp) proto_release(pp); - free(pp); - } } } - proto_release(&g_func_pp); + g_func_pp = NULL; } static void set_label(int i, const char *name) diff --git a/win32.hlist b/win32.hlist index 5632296..091ec93 100644 --- a/win32.hlist +++ b/win32.hlist @@ -12,9 +12,7 @@ WINBASEAPI BOOL WINAPI CreateDirectoryExW(LPCWSTR,LPCWSTR,LPSECURITY_ATTRIBUTES) WINBASEAPI HANDLE WINAPI CreateEventA(LPSECURITY_ATTRIBUTES,BOOL,BOOL,LPCSTR); WINBASEAPI HANDLE WINAPI CreateEventW(LPSECURITY_ATTRIBUTES,BOOL,BOOL,LPCWSTR); WINBASEAPI LPVOID WINAPI CreateFiber(SIZE_T,LPFIBER_START_ROUTINE,LPVOID); -#if (_WIN32_WINNT >= 0x0400) WINBASEAPI LPVOID WINAPI CreateFiberEx(SIZE_T,SIZE_T,DWORD,LPFIBER_START_ROUTINE,LPVOID); -#endif WINBASEAPI HANDLE WINAPI CreateFileA(LPCSTR,DWORD,DWORD,LPSECURITY_ATTRIBUTES,DWORD,DWORD,HANDLE); WINBASEAPI HANDLE WINAPI CreateFileW(LPCWSTR,DWORD,DWORD,LPSECURITY_ATTRIBUTES,DWORD,DWORD,HANDLE); WINBASEAPI BOOL WINAPI CreateProcessA(LPCSTR,LPSTR,LPSECURITY_ATTRIBUTES,LPSECURITY_ATTRIBUTES,BOOL,DWORD,PVOID,LPCSTR,LPSTARTUPINFOA,LPPROCESS_INFORMATION); -- 2.39.2