header pre-parsing
authornotaz <notasas@gmail.com>
Mon, 30 Dec 2013 23:54:22 +0000 (01:54 +0200)
committernotaz <notasas@gmail.com>
Mon, 30 Dec 2013 23:54:22 +0000 (01:54 +0200)
tools/mkbridge.c
tools/protoparse.h
tools/translate.c
win32.hlist

index 5bcd84a..3b3f4ce 100644 (file)
@@ -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;
index 267ef73..673fcb7 100644 (file)
@@ -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);
 }
index 7c7390e..7cbf8b7 100644 (file)
@@ -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)
index 5632296..091ec93 100644 (file)
@@ -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);