minor fixes
[ia32rtools.git] / tools / protoparse.h
index 93129a1..8e88ba0 100644 (file)
@@ -15,14 +15,17 @@ struct parsed_type {
        unsigned int is_struct:1; // split for args
        unsigned int is_retreg:1; // register to return to caller
        unsigned int is_va_list:1;
+       unsigned int is_64bit:1;
+       unsigned int is_float:1;  // float, double
 };
 
 struct parsed_proto_arg {
        char *reg;
        struct parsed_type type;
        struct parsed_proto *pp; // fptr or struct
-       void *datap;
        unsigned int is_saved:1; // not set here, for tool use
+       void **push_refs;
+       int push_ref_cnt;
 };
 
 struct parsed_proto {
@@ -31,7 +34,7 @@ struct parsed_proto {
                struct parsed_type ret_type;
                struct parsed_type type;
        };
-       struct parsed_proto_arg arg[16];
+       struct parsed_proto_arg arg[32];
        int argc;
        int argc_stack;
        int argc_reg;
@@ -40,8 +43,10 @@ struct parsed_proto {
        unsigned int is_fastcall:1;
        unsigned int is_vararg:1;     // vararg func
        unsigned int is_fptr:1;
+       unsigned int is_import:1;     // data import
        unsigned int is_noreturn:1;
        unsigned int is_unresolved:1;
+       unsigned int is_guessed:1;    // for extra checking
        unsigned int is_userstack:1;
        unsigned int is_include:1;    // not from top-level header
        unsigned int is_osinc:1;      // OS/system library func
@@ -211,11 +216,15 @@ static const char *known_ptr_types[] = {
        "HRGN",
        "HRSRC",
        "HKEY",
+       "HKL",
        "HMENU",
+       "HMONITOR",
        "HWAVEOUT",
        "HWND",
+       "PAPPBARDATA",
        "PBYTE",
        "PCRITICAL_SECTION",
+       "PDEVMODEA",
        "PDWORD",
        "PFILETIME",
        "PLARGE_INTEGER",
@@ -230,7 +239,10 @@ static const char *known_ptr_types[] = {
        "PCVOID",
        "PWORD",
        "REFCLSID",
+       "REFGUID",
        "REFIID",
+       "SC_HANDLE",
+       "SERVICE_STATUS_HANDLE",
        "HOOKPROC",
        "DLGPROC",
        "TIMERPROC",
@@ -241,6 +253,7 @@ static const char *known_ptr_types[] = {
 
 static const char *ignored_keywords[] = {
        "extern",
+       "static",
        "WINBASEAPI",
        "WINUSERAPI",
        "WINGDIAPI",
@@ -397,6 +410,9 @@ static int parse_arg(char **p_, struct parsed_proto_arg *arg, int xarg)
        if (ret < 0)
                return -1;
 
+       if (IS_START(arg->pp->name, "guess"))
+               arg->pp->is_guessed = 1;
+
        // we don't use actual names right now...
        snprintf(arg->pp->name, sizeof(arg->pp->name), "a%d", xarg);
 
@@ -457,6 +473,11 @@ static int parse_protostr(char *protostr, struct parsed_proto *pp)
                        p = sskip(p + l + 1);
        }
 
+       if (IS_START(p, "DECL_IMPORT ")) {
+               pp->is_import = 1;
+               p = sskip(p + 12);
+       }
+
        ret = check_type(p, &pp->ret_type);
        if (ret <= 0) {
                printf("%s:%d:%zd: unhandled return in '%s'\n",
@@ -623,6 +644,12 @@ static int parse_protostr(char *protostr, struct parsed_proto *pp)
                        return -1;
                }
 
+               if (xarg >= ARRAY_SIZE(pp->arg)) {
+                       printf("%s:%d:%zd: too many args\n",
+                               hdrfn, hdrfline, (p - protostr) + 1);
+                       return -1;
+               }
+
                arg = &pp->arg[xarg];
                xarg++;
 
@@ -667,14 +694,22 @@ static int parse_protostr(char *protostr, struct parsed_proto *pp)
                        pp->has_retreg |= is_retreg;
                }
 
+               if (IS(arg->type.name, "float")
+                     || IS(arg->type.name, "double"))
+               {
+                       arg->type.is_float = 1;
+               }
+
                if (!arg->type.is_ptr && (strstr(arg->type.name, "int64")
                      || IS(arg->type.name, "double")))
                {
+                       arg->type.is_64bit = 1;
                        // hack..
-                       free(arg->type.name);
-                       arg->type.name = strdup("int");
                        pp_copy_arg(&pp->arg[xarg], arg);
+                       arg = &pp->arg[xarg];
                        xarg++;
+                       free(arg->type.name);
+                       arg->type.name = strdup("dummy");
                }
 
                ret = check_struct_arg(arg);
@@ -967,22 +1002,43 @@ static inline int pp_cmp_func(const struct parsed_proto *pp1,
 
   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;
-      }
+  if (pp1->is_stdcall != pp2->is_stdcall)
+    return 1;
+
+  // because of poor void return detection, return is not
+  // checked for now to avoid heaps of false positives
+
+  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 int pp_compatible_func(
+  const struct parsed_proto *pp_site,
+  const struct parsed_proto *pp_callee)
+{
+  if (pp_cmp_func(pp_site, pp_callee) == 0)
+    return 1;
+
+  if (pp_site->argc_stack == 0 && pp_site->is_fastcall
+      && pp_callee->argc_stack == 0
+      && (pp_callee->is_fastcall || pp_callee->argc_reg == 0)
+      && pp_site->argc_reg > pp_callee->argc_reg)
+    /* fascall compatible callee doesn't use all args -> ok */
+    return 1;
+
+  return 0;
+}
+
 static inline void pp_print(char *buf, size_t buf_size,
   const struct parsed_proto *pp)
 {
@@ -1010,12 +1066,10 @@ static inline void proto_release(struct parsed_proto *pp)
        int i;
 
        for (i = 0; i < pp->argc; i++) {
-               if (pp->arg[i].reg != NULL)
-                       free(pp->arg[i].reg);
-               if (pp->arg[i].type.name != NULL)
-                       free(pp->arg[i].type.name);
-               if (pp->arg[i].pp != NULL)
-                       free(pp->arg[i].pp);
+               free(pp->arg[i].reg);
+               free(pp->arg[i].type.name);
+               free(pp->arg[i].pp);
+               free(pp->arg[i].push_refs);
        }
        if (pp->ret_type.name != NULL)
                free(pp->ret_type.name);