more wip, handle C calls
authornotaz <notasas@gmail.com>
Mon, 16 Dec 2013 00:39:05 +0000 (02:39 +0200)
committernotaz <notasas@gmail.com>
Mon, 16 Dec 2013 00:39:05 +0000 (02:39 +0200)
stdc.hlst [new file with mode: 0644]
tools/protoparse.h
tools/translate.c

diff --git a/stdc.hlst b/stdc.hlst
new file mode 100644 (file)
index 0000000..260c869
--- /dev/null
+++ b/stdc.hlst
@@ -0,0 +1,88 @@
+int __cdecl    rand    (void);
+void __cdecl   srand   (unsigned int);
+void* __cdecl  calloc  (size_t, size_t);
+void* __cdecl  malloc  (size_t);
+void* __cdecl  realloc (void*, size_t);
+void __cdecl   free    (void*);
+void __cdecl   abort   (void);
+void __cdecl   exit    (int);
+int __cdecl    atexit  (void (__cdecl *)(void));
+int __cdecl    system  (const char*);
+char* __cdecl  getenv  (const char*);
+void* __cdecl bsearch (const void*, const void*, size_t, size_t, int (__cdecl *)(const void*, const void*));
+void __cdecl qsort(void*, size_t, size_t, int (__cdecl *)(const void*, const void*));
+int __cdecl    abs     (int);
+long __cdecl   labs    (long);
+long __cdecl   strtol  (const char*, char**, int);
+unsigned long __cdecl  strtoul (const char*, char**, int);
+
+void* __cdecl  memchr (const void*, int, size_t);
+int __cdecl    memcmp (const void*, const void*, size_t);
+void* __cdecl          memcpy (void*, const void*, size_t);
+void* __cdecl  memmove (void*, const void*, size_t);
+void* __cdecl  memset (void*, int, size_t);
+char* __cdecl  strcat (char*, const char*);
+char* __cdecl  strchr (const char*, int) ;
+int __cdecl    strcmp (const char*, const char*);
+int __cdecl    strcoll (const char*, const char*);
+char* __cdecl  strcpy (char*, const char*);
+size_t __cdecl         strcspn (const char*, const char*);
+char* __cdecl  strerror (int);
+double __cdecl         atof    (const char*);
+int __cdecl    atoi    (const char*);
+long __cdecl   atol    (const char*);
+
+size_t __cdecl         strlen (const char*) ;
+char* __cdecl  strncat (char*, const char*, size_t);
+int __cdecl    strncmp (const char*, const char*, size_t) ;
+char* __cdecl  strncpy (char*, const char*, size_t);
+char* __cdecl  strpbrk (const char*, const char*) ;
+char* __cdecl  strrchr (const char*, int) ;
+size_t __cdecl         strspn (const char*, const char*) ;
+char* __cdecl  strstr (const char*, const char*) ;
+char* __cdecl  strtok (char*, const char*);
+size_t __cdecl         strxfrm (char*, const char*, size_t);
+
+int __cdecl  isalnum(int);
+int __cdecl  isalpha(int);
+int __cdecl  iscntrl(int);
+int __cdecl  isdigit(int);
+int __cdecl  isgraph(int);
+int __cdecl  islower(int);
+int __cdecl  isprint(int);
+int __cdecl  ispunct(int);
+int __cdecl  isspace(int);
+int __cdecl  isupper(int);
+int __cdecl  isxdigit(int);
+int __cdecl  tolower(int);
+int __cdecl  toupper(int);
+
+char* __cdecl          asctime (const struct tm*);
+char* __cdecl          ctime (const time_t*);
+struct tm*  __cdecl    gmtime (const time_t*);
+struct tm*  __cdecl    localtime (const time_t*);
+size_t __cdecl                 strftime (char*, size_t, const char*, const struct tm*);
+extern void __cdecl    _tzset (void);
+extern void __cdecl    tzset (void);
+
+FILE* __cdecl  fopen (const char*, const char*);
+FILE* __cdecl  freopen (const char*, const char*, FILE*);
+int __cdecl    fflush (FILE*);
+int __cdecl    fclose (FILE*);
+int __cdecl    remove (const char*);
+int __cdecl    rename (const char*, const char*);
+FILE* __cdecl  tmpfile (void);
+char* __cdecl  tmpnam (char*);
+char* __cdecl  _tempnam (const char*, const char*);
+int __cdecl    _rmtmp(void);
+int __cdecl    _unlink (const char*);
+char* __cdecl  tempnam (const char*, const char*);
+int __cdecl    rmtmp(void);
+int __cdecl    unlink (const char*);
+int __cdecl    setvbuf (FILE*, char*, int, size_t);
+void __cdecl   setbuf (FILE*, char*);
+size_t __cdecl         fread (void*, size_t, size_t, FILE*);
+size_t __cdecl         fwrite (const void*, size_t, size_t, FILE*);
+int __cdecl    fseek (FILE*, long, int);
+long __cdecl   ftell (FILE*);
+void __cdecl   rewind (FILE*);
index c102c49..533dd46 100644 (file)
@@ -1,31 +1,68 @@
 
+struct parsed_proto;
+
+struct parsed_proto_arg {
+       char *reg;
+       const char *type;
+       struct parsed_proto *fptr;
+       void *datap;
+};
+
 struct parsed_proto {
-       struct {
-               char *reg;
-               const char *type;
-               void *datap;
-       } arg[16];
+       char name[256];
        const char *ret_type;
-       int is_stdcall;
+       struct parsed_proto_arg arg[16];
        int argc;
        int argc_stack;
        int argc_reg;
+       unsigned int is_stdcall:1;
+       unsigned int is_fptr:1;
 };
 
 static const char *hdrfn;
 static int hdrfline = 0;
 
-static int find_protostr(char *dst, size_t dlen, FILE *fhdr, const char *sym)
+static int find_protostr(char *dst, size_t dlen, FILE *fhdr,
+       const char *fname, const char *sym_)
 {
+       const char *sym = sym_;
+       FILE *finc;
+       int symlen;
        int line = 0;
+       int ret;
        char *p;
 
+       if (sym[0] == '_' && strncmp(fname, "stdc", 4) == 0)
+               sym++;
+       symlen = strlen(sym);
+
        rewind(fhdr);
 
        while (fgets(dst, dlen, fhdr))
        {
                line++;
-               if (strstr(dst, sym) != NULL)
+               if (strncmp(dst, "#include ", 9) == 0) {
+                       p = strpbrk(dst + 9, "\r\n ");
+                       if (p != NULL)
+                               *p = 0;
+
+                       finc = fopen(dst + 9, "r");
+                       if (finc == NULL) {
+                               printf("%s:%d: can't open '%s'\n",
+                                       fname, line, dst + 9);
+                               continue;
+                       }
+                       ret = find_protostr(dst, dlen, finc,
+                               dst + 9, sym_);
+                       fclose(finc);
+                       if (ret == 0)
+                               break;
+                       continue;
+               }
+
+               p = strstr(dst, sym);
+               if (p != NULL
+                  && (my_isblank(p[symlen]) || my_issep(p[symlen])))
                        break;
        }
        hdrfline = line;
@@ -86,13 +123,26 @@ static const char *known_types[] = {
        "size_t",
 };
 
+static int typecmp(const char *n, const char *t)
+{
+       for (; *t != 0; n++, t++) {
+               while (n[0] == ' ' && (n[1] == ' ' || n[1] == '*'))
+                       n++;
+               while (t[0] == ' ' && (t[1] == ' ' || t[1] == '*'))
+                       t++;
+               if (*n != *t)
+                       return *n - *t;
+       }
+
+       return 0;
+}
+
 static const char *check_type(const char *name)
 {
-       int i, l;
+       int i;
 
        for (i = 0; i < ARRAY_SIZE(known_types); i++) {
-               l = strlen(known_types[i]);
-               if (strncmp(known_types[i], name, l) == 0)
+               if (typecmp(name, known_types[i]) == 0)
                        return known_types[i];
        }
 
@@ -120,13 +170,14 @@ static const char *map_reg(const char *reg)
 
 static int parse_protostr(char *protostr, struct parsed_proto *pp)
 {
+       struct parsed_proto_arg *arg;
        char regparm[16];
        char buf[256];
        char cconv[32];
        const char *kt;
        int xarg = 0;
+       char *p, *p1;
        int ret;
-       char *p;
        int i;
 
        p = protostr;
@@ -139,18 +190,23 @@ static int parse_protostr(char *protostr, struct parsed_proto *pp)
        if (kt == NULL) {
                printf("%s:%d:%ld: unhandled return in '%s'\n",
                        hdrfn, hdrfline, (p - protostr) + 1, protostr);
-               return 1;
+               return -1;
        }
        pp->ret_type = kt;
        p += strlen(kt);
        p = sskip(p);
 
+       if (*p == '(') {
+               pp->is_fptr = 1;
+               p = sskip(p + 1);
+       }
+
        p = next_word(cconv, sizeof(cconv), p);
        p = sskip(p);
        if (cconv[0] == 0) {
                printf("%s:%d:%ld: cconv missing\n",
                        hdrfn, hdrfline, (p - protostr) + 1);
-               return 1;
+               return -1;
        }
        if      (IS(cconv, "__cdecl"))
                pp->is_stdcall = 0;
@@ -167,16 +223,26 @@ static int parse_protostr(char *protostr, struct parsed_proto *pp)
        else {
                printf("%s:%d:%ld: unhandled cconv: '%s'\n",
                        hdrfn, hdrfline, (p - protostr) + 1, cconv);
-               return 1;
+               return -1;
+       }
+
+       if (pp->is_fptr) {
+               if (*p != '*') {
+                       printf("%s:%d:%ld: '*' expected\n",
+                               hdrfn, hdrfline, (p - protostr) + 1);
+                       return -1;
+               }
+               p = sskip(p + 1);
        }
 
        p = next_idt(buf, sizeof(buf), p);
        p = sskip(p);
        if (buf[0] == 0) {
                printf("%s:%d:%ld: func name missing\n",
-                               hdrfn, hdrfline, (p - protostr) + 1);
-               return 1;
+                       hdrfn, hdrfline, (p - protostr) + 1);
+               return -1;
        }
+       strcpy(pp->name, buf);
 
        ret = get_regparm(regparm, sizeof(regparm), p);
        if (ret > 0) {
@@ -185,55 +251,88 @@ static int parse_protostr(char *protostr, struct parsed_proto *pp)
                {
                        printf("%s:%d:%ld: bad regparm: %s\n",
                                hdrfn, hdrfline, (p - protostr) + 1, regparm);
-                       return 1;
+                       return -1;
                }
                p += ret;
                p = sskip(p);
        }
 
+       if (pp->is_fptr) {
+               if (*p != ')') {
+                       printf("%s:%d:%ld: ')' expected\n",
+                               hdrfn, hdrfline, (p - protostr) + 1);
+                       return -1;
+               }
+               p = sskip(p + 1);
+       }
+
        if (*p != '(') {
                printf("%s:%d:%ld: '(' expected, got '%c'\n",
                                hdrfn, hdrfline, (p - protostr) + 1, *p);
-               return 1;
+               return -1;
        }
        p++;
 
+       // check for x(void)
+       p = sskip(p);
+       if (strncmp(p, "void", 4) == 0 && *sskip(p + 4) == ')')
+               p += 4;
+
        while (1) {
                p = sskip(p);
-               if (*p == ')')
+               if (*p == ')') {
+                       p++;
                        break;
+               }
                if (*p == ',')
                        p = sskip(p + 1);
 
+               arg = &pp->arg[xarg];
                xarg++;
 
+               p1 = p;
                kt = check_type(p);
                if (kt == NULL) {
                        printf("%s:%d:%ld: unhandled type for arg%d\n",
                                hdrfn, hdrfline, (p - protostr) + 1, xarg);
-                       return 1;
+                       return -1;
                }
-               pp->arg[xarg - 1].type = kt;
+               arg->type = kt;
                p += strlen(kt);
                p = sskip(p);
 
+               if (*p == '(') {
+                       // func ptr
+                       arg->fptr = calloc(1, sizeof(*arg->fptr));
+                       ret = parse_protostr(p1, arg->fptr);
+                       if (ret < 0) {
+                               printf("%s:%d:%ld: funcarg parse failed\n",
+                                       hdrfn, hdrfline, p1 - protostr);
+                               return -1;
+                       }
+                       // we'll treat it as void * for non-calls
+                       arg->type = "void *";
+
+                       p = p1 + ret;
+               }
+
                p = next_idt(buf, sizeof(buf), p);
                p = sskip(p);
 #if 0
                if (buf[0] == 0) {
                        printf("%s:%d:%ld: idt missing for arg%d\n",
                                hdrfn, hdrfline, (p - protostr) + 1, xarg);
-                       return 1;
+                       return -1;
                }
 #endif
-               pp->arg[xarg - 1].reg = NULL;
+               arg->reg = NULL;
 
                ret = get_regparm(regparm, sizeof(regparm), p);
                if (ret > 0) {
                        p += ret;
                        p = sskip(p);
 
-                       pp->arg[xarg - 1].reg = strdup(map_reg(regparm));
+                       arg->reg = strdup(map_reg(regparm));
                }
        }
 
@@ -262,7 +361,7 @@ static int parse_protostr(char *protostr, struct parsed_proto *pp)
                        pp->argc_reg++;
        }
 
-       return 0;
+       return p - protostr;
 }
 
 static int proto_parse(FILE *fhdr, const char *sym, struct parsed_proto *pp)
@@ -272,13 +371,13 @@ static int proto_parse(FILE *fhdr, const char *sym, struct parsed_proto *pp)
 
        memset(pp, 0, sizeof(*pp));
 
-       ret = find_protostr(protostr, sizeof(protostr), fhdr, sym);
+       ret = find_protostr(protostr, sizeof(protostr), fhdr, hdrfn, sym);
        if (ret != 0) {
                printf("%s: sym '%s' is missing\n", hdrfn, sym);
                return ret;
        }
 
-       return parse_protostr(protostr, pp);
+       return parse_protostr(protostr, pp) < 0 ? -1 : 0;
 }
 
 static void proto_release(struct parsed_proto *pp)
@@ -286,7 +385,9 @@ static void proto_release(struct parsed_proto *pp)
        int i;
 
        for (i = 0; i < pp->argc; i++) {
-               if (pp->arg[i].reg == NULL)
+               if (pp->arg[i].reg != NULL)
                        free(pp->arg[i].reg);
+               if (pp->arg[i].fptr != NULL)
+                       free(pp->arg[i].fptr);
        }
 }
index fbc8ff6..532c160 100644 (file)
@@ -8,6 +8,7 @@
 
 #define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
 #define IS(w, y) !strcmp(w, y)
+#define IS_START(w, y) !strncmp(w, y, strlen(y))
 
 #include "protoparse.h"
 
@@ -294,7 +295,7 @@ static int parse_indmode(char *name, int *regmask, int need_c_cvt)
     *d = 0;
 
     // skip 'ds:' prefix
-    if (!strncmp(s, "ds:", 3))
+    if (IS_START(s, "ds:"))
       s += 3;
 
     s = next_idt(w, sizeof(w), s);
@@ -334,12 +335,12 @@ static const char *parse_stack_el(const char *name)
   long val;
   int len;
 
-  if (!strncmp(name, "ebp+", 4)
+  if (IS_START(name, "ebp+")
       && !('0' <= name[4] && name[4] <= '9'))
   {
     return name + 4;
   }
-  if (strncmp(name, "esp+", 4) != 0)
+  if (!IS_START(name, "esp+"))
     return NULL;
 
   p = strchr(name + 4, '+');
@@ -399,7 +400,8 @@ static void setup_reg_opr(struct parsed_opr *opr, int reg, enum opr_lenmod lmod,
   *regmask |= 1 << reg;
 }
 
-static struct parsed_equ *equ_find(struct parsed_op *po, const char *name);
+static struct parsed_equ *equ_find(struct parsed_op *po, const char *name,
+  int *extra_offs);
 
 static int parse_operand(struct parsed_opr *opr,
   int *regmask, int *regmask_indirect,
@@ -409,6 +411,7 @@ static int parse_operand(struct parsed_opr *opr,
   int ret, len;
   long number;
   int wordc_in;
+  char *tmp;
   int i;
 
   if (w >= wordc)
@@ -444,6 +447,8 @@ static int parse_operand(struct parsed_opr *opr,
 
     if (label != NULL) {
       opr->type = OPT_LABEL;
+      if (IS_START(label, "ds:"))
+        label += 3;
       strcpy(opr->name, label);
       return wordc;
     }
@@ -464,16 +469,30 @@ static int parse_operand(struct parsed_opr *opr,
     }
   }
 
-  if (wordc_in == 2 && IS(words[w], "offset")) {
-    opr->type = OPT_OFFSET;
-    strcpy(opr->name, words[w + 1]);
-    return wordc;
+  if (wordc_in == 2) {
+    if (IS(words[w], "offset")) {
+      opr->type = OPT_OFFSET;
+      strcpy(opr->name, words[w + 1]);
+      return wordc;
+    }
+    if (IS(words[w], "(offset")) {
+      char *p = strchr(words[w + 1], ')');
+      if (p == NULL)
+        aerr("parse of bracketed offset failed\n");
+      *p = 0;
+      opr->type = OPT_OFFSET;
+      strcpy(opr->name, words[w + 1]);
+      return wordc;
+    }
   }
 
   if (wordc_in != 1)
     aerr("parse_operand 1 word expected\n");
 
-  strcpy(opr->name, words[w]);
+  tmp = words[w];
+  if (IS_START(tmp, "ds:"))
+    tmp += 3;
+  strcpy(opr->name, tmp);
 
   if (words[w][0] == '[') {
     opr->type = OPT_REGMEM;
@@ -485,7 +504,7 @@ static int parse_operand(struct parsed_opr *opr,
     if (opr->lmod == OPLM_UNSPEC && parse_stack_el(opr->name)) {
       // might be an equ
       struct parsed_equ *eq =
-        equ_find(NULL, parse_stack_el(opr->name));
+        equ_find(NULL, parse_stack_el(opr->name), &i);
       if (eq)
         opr->lmod = eq->lmod;
     }
@@ -905,12 +924,33 @@ static const char *opr_reg_p(struct parsed_op *po, struct parsed_opr *popr)
   return regs_r32[popr->reg];
 }
 
-static struct parsed_equ *equ_find(struct parsed_op *po, const char *name)
+static struct parsed_equ *equ_find(struct parsed_op *po, const char *name,
+  int *extra_offs)
 {
+  const char *p;
+  char *endp;
+  int namelen;
   int i;
 
+  *extra_offs = 0;
+  namelen = strlen(name);
+
+  p = strchr(name, '+');
+  if (p != NULL) {
+    namelen = p - name;
+    if (namelen <= 0)
+      ferr(po, "equ parse failed for '%s'\n", name);
+
+    if (IS_START(p, "0x"))
+      p += 2;
+    *extra_offs = strtol(p, &endp, 16);
+    if (*endp != 0)
+      ferr(po, "equ parse failed for '%s'\n", name);
+  }
+
   for (i = 0; i < g_eqcnt; i++)
-    if (IS(g_eqs[i].name, name))
+    if (strncmp(g_eqs[i].name, name, namelen) == 0
+     && g_eqs[i].name[namelen] == 0)
       break;
   if (i >= g_eqcnt) {
     if (po != NULL)
@@ -930,25 +970,28 @@ static void stack_frame_access(struct parsed_op *po,
   int i, arg_i, arg_s;
   const char *bp_arg;
   int stack_ra = 0;
+  int offset = 0;
   int sf_ofs;
 
   bp_arg = parse_stack_el(name);
   snprintf(g_comment, sizeof(g_comment), "%s", bp_arg);
-  eq = equ_find(po, bp_arg);
+  eq = equ_find(po, bp_arg, &offset);
   if (eq == NULL)
     ferr(po, "detected but missing eq\n");
 
+  offset += eq->offset;
+
   if (!strncmp(name, "ebp", 3))
     stack_ra = 4;
 
-  if (stack_ra <= eq->offset && eq->offset < stack_ra + 4)
-    ferr(po, "reference to ra? %d %d\n", eq->offset, stack_ra);
+  if (stack_ra <= offset && offset < stack_ra + 4)
+    ferr(po, "reference to ra? %d %d\n", offset, stack_ra);
 
-  if (eq->offset > stack_ra) {
-    arg_i = (eq->offset - stack_ra - 4) / 4;
+  if (offset > stack_ra) {
+    arg_i = (offset - stack_ra - 4) / 4;
     if (arg_i < 0 || arg_i >= g_func_pp.argc_stack)
       ferr(po, "offset %d (%s) doesn't map to any arg\n",
-        eq->offset, bp_arg);
+        offset, bp_arg);
 
     for (i = arg_s = 0; i < g_func_pp.argc; i++) {
       if (g_func_pp.arg[i].reg != NULL)
@@ -968,9 +1011,9 @@ static void stack_frame_access(struct parsed_op *po,
     if (g_stack_fsz == 0)
       ferr(po, "stack var access without stackframe\n");
 
-    sf_ofs = g_stack_fsz + eq->offset;
+    sf_ofs = g_stack_fsz + offset;
     if (sf_ofs < 0)
-      ferr(po, "bp_stack offset %d/%d\n", eq->offset, g_stack_fsz);
+      ferr(po, "bp_stack offset %d/%d\n", offset, g_stack_fsz);
 
     if (is_lea)
       prefix = "(u32)&";
@@ -1744,6 +1787,15 @@ static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt)
         ops[ret].flags |= OPF_RMD;
       }
 
+      // can't call functions with non-__cdecl callbacks yet
+      for (arg = 0; arg < pp->argc; arg++) {
+        if (pp->arg[arg].fptr != NULL) {
+          pp_tmp = pp->arg[arg].fptr;
+          if (pp_tmp->is_stdcall || pp_tmp->argc != pp_tmp->argc_stack)
+            ferr(po, "'%s' has a non-__cdecl callback\n", tmpname);
+        }
+      }
+
       for (arg = 0; arg < pp->argc; arg++)
         if (pp->arg[arg].reg == NULL)
           break;
@@ -2334,10 +2386,15 @@ static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt)
             fprintf(fout, "(u32)");
         }
 
-        if (po->operand[0].type != OPT_LABEL)
+        if (po->operand[0].type != OPT_LABEL) {
           fprintf(fout, "icall%d(", i);
-        else
-          fprintf(fout, "%s(", opr_name(po, 0));
+        }
+        else {
+          if (pp->name[0] == 0)
+            ferr(po, "missing pp->name\n");
+          fprintf(fout, "%s(", pp->name);
+        }
+
         for (arg = 0; arg < pp->argc; arg++) {
           if (arg > 0)
             fprintf(fout, ", ");