translate: hdrgen: detect strings, skip std funcs
[ia32rtools.git] / tools / protoparse.h
index ab16632..3d70d86 100644 (file)
@@ -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 {
@@ -28,11 +37,16 @@ struct parsed_proto {
        unsigned int is_func:1;
        unsigned int is_stdcall:1;
        unsigned int is_fastcall:1;
-       unsigned int is_vararg: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;
@@ -41,15 +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;
@@ -58,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++;
@@ -82,7 +101,7 @@ static int do_protostrs(FILE *fhdr, const char *fname)
                                        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;
@@ -99,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;
        }
@@ -112,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] == '>')
@@ -144,9 +172,11 @@ static const char *known_type_mod[] = {
 static const char *known_ptr_types[] = {
        "FARPROC",
        "WNDPROC",
+       "LINECALLBACK",
        "HACCEL",
        "HANDLE",
        "HBITMAP",
+       "HCALL",
        "HCURSOR",
        "HDC",
        "HFONT",
@@ -154,23 +184,30 @@ static const char *known_ptr_types[] = {
        "HGLOBAL",
        "HICON",
        "HINSTANCE",
-       //"HIMC", // DWORD
+       "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",
@@ -259,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);
 
@@ -298,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;
@@ -386,6 +426,10 @@ static int parse_protostr(char *protostr, struct parsed_proto *pp)
                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 {
@@ -416,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"))
@@ -510,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;
@@ -528,12 +576,14 @@ 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")
@@ -614,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;
 
@@ -632,6 +683,8 @@ 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;
 }
@@ -644,7 +697,7 @@ static void build_pp_cache(FILE *fhdr)
        pos = ftell(fhdr);
        rewind(fhdr);
 
-       ret = do_protostrs(fhdr, hdrfn);
+       ret = do_protostrs(fhdr, hdrfn, 0);
        if (ret < 0)
                exit(1);
 
@@ -657,6 +710,7 @@ static const struct parsed_proto *proto_parse(FILE *fhdr, const char *sym,
 {
        const struct parsed_proto *pp_ret;
        struct parsed_proto pp_search;
+       char *p;
 
        if (pp_cache == NULL)
                build_pp_cache(fhdr);
@@ -665,6 +719,10 @@ 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 && !quiet)
@@ -711,6 +769,30 @@ 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)
 {