translate: support for data imports
[ia32rtools.git] / tools / protoparse.h
CommitLineData
7637b6cc 1/*
2 * ia32rtools
3 * (C) notaz, 2013,2014
4 *
5 * This work is licensed under the terms of 3-clause BSD license.
6 * See COPYING file in the top-level directory.
7 */
c36e914d 8
39b168b8 9struct parsed_proto;
10
3ebea2cf 11struct parsed_type {
12 char *name;
13 unsigned int is_array:1;
14 unsigned int is_ptr:1;
a652aa9f 15 unsigned int is_struct:1; // split for args
5f70a34f 16 unsigned int is_retreg:1; // register to return to caller
17 unsigned int is_va_list:1;
2c31fb4c 18 unsigned int is_64bit:1;
b62264bc 19 unsigned int is_float:1; // float, double
3ebea2cf 20};
21
39b168b8 22struct parsed_proto_arg {
23 char *reg;
3ebea2cf 24 struct parsed_type type;
93b5bd18 25 struct parsed_proto *pp; // fptr or struct
39b168b8 26 void *datap;
8c83cc48 27 unsigned int is_saved:1; // not set here, for tool use
39b168b8 28};
29
c36e914d 30struct parsed_proto {
39b168b8 31 char name[256];
3ebea2cf 32 union {
33 struct parsed_type ret_type;
34 struct parsed_type type;
35 };
39b168b8 36 struct parsed_proto_arg arg[16];
c36e914d 37 int argc;
38 int argc_stack;
39 int argc_reg;
06c5d854 40 unsigned int is_func:1;
39b168b8 41 unsigned int is_stdcall:1;
c0050df6 42 unsigned int is_fastcall:1;
efea2951 43 unsigned int is_vararg:1; // vararg func
39b168b8 44 unsigned int is_fptr:1;
1fe8d40e 45 unsigned int is_import:1; // data import
e56ab892 46 unsigned int is_noreturn:1;
89ff3147 47 unsigned int is_unresolved:1;
1fe8d40e 48 unsigned int is_guessed:1; // for extra checking
1f84f6b3 49 unsigned int is_userstack:1;
61e29183 50 unsigned int is_include:1; // not from top-level header
51 unsigned int is_osinc:1; // OS/system library func
ebc4dc43 52 unsigned int is_cinc:1; // crt library func
179b79a9 53 unsigned int is_arg:1; // declared in some func arg
a652aa9f 54 unsigned int has_structarg:1;
1f84f6b3 55 unsigned int has_retreg:1;
c36e914d 56};
57
865f1aca 58struct parsed_struct {
59 char name[256];
60 struct {
61 int offset;
62 struct parsed_proto pp;
63 } members[64];
64 int member_count;
65};
66
c36e914d 67static const char *hdrfn;
68static int hdrfline = 0;
69
a652aa9f 70static void pp_copy_arg(struct parsed_proto_arg *d,
71 const struct parsed_proto_arg *s);
72
61e29183 73static int b_pp_c_handler(char *proto, const char *fname,
ebc4dc43 74 int is_include, int is_osinc, int is_cinc);
865f1aca 75static int struct_handler(FILE *fhdr, char *proto, int *line);
bd96f656 76
61e29183 77static int do_protostrs(FILE *fhdr, const char *fname, int is_include)
c36e914d 78{
06c5d854 79 const char *finc_name;
bd96f656 80 const char *hdrfn_saved;
81 char protostr[256];
36595fd2 82 char path[256];
83 char fname_inc[256];
61e29183 84 int is_osinc;
ebc4dc43 85 int is_cinc;
39b168b8 86 FILE *finc;
c36e914d 87 int line = 0;
39b168b8 88 int ret;
c36e914d 89 char *p;
90
bd96f656 91 hdrfn_saved = hdrfn;
92 hdrfn = fname;
39b168b8 93
ebc4dc43 94 is_cinc = strstr(fname, "stdc.hlist") != NULL;
edeadc28 95 is_osinc = is_cinc || strstr(fname, "win32.hlist") != NULL;
179b79a9 96
bd96f656 97 while (fgets(protostr, sizeof(protostr), fhdr))
c36e914d 98 {
99 line++;
bd96f656 100 if (strncmp(protostr, "//#include ", 11) == 0) {
101 finc_name = protostr + 11;
06c5d854 102 p = strpbrk(finc_name, "\r\n ");
39b168b8 103 if (p != NULL)
104 *p = 0;
105
36595fd2 106 path[0] = 0;
107 p = strrchr(hdrfn_saved, '/');
108 if (p) {
109 memcpy(path, hdrfn_saved,
110 p - hdrfn_saved + 1);
111 path[p - hdrfn_saved + 1] = 0;
112 }
113 snprintf(fname_inc, sizeof(fname_inc), "%s%s",
114 path, finc_name);
115 finc = fopen(fname_inc, "r");
39b168b8 116 if (finc == NULL) {
117 printf("%s:%d: can't open '%s'\n",
36595fd2 118 fname_inc, line, finc_name);
39b168b8 119 continue;
120 }
61e29183 121 ret = do_protostrs(finc, finc_name, 1);
39b168b8 122 fclose(finc);
bd96f656 123 if (ret < 0)
39b168b8 124 break;
125 continue;
126 }
bd96f656 127 if (strncmp(sskip(protostr), "//", 2) == 0)
128 continue;
129
130 p = protostr + strlen(protostr);
131 for (p--; p >= protostr && my_isblank(*p); --p)
132 *p = 0;
133 if (p < protostr)
06c5d854 134 continue;
39b168b8 135
bd96f656 136 hdrfline = line;
137
865f1aca 138 if (!strncmp(protostr, "struct", 6)
139 && strchr(protostr, '{') != NULL)
140 ret = struct_handler(fhdr, protostr, &line);
141 else
142 ret = b_pp_c_handler(protostr, hdrfn,
143 is_include, is_osinc, is_cinc);
bd96f656 144 if (ret < 0)
c36e914d 145 break;
146 }
c36e914d 147
bd96f656 148 hdrfn = hdrfn_saved;
c36e914d 149
bd96f656 150 if (feof(fhdr))
151 return 0;
c36e914d 152
bd96f656 153 return -1;
c36e914d 154}
155
1f84f6b3 156static int get_regparm(char *dst, size_t dlen, char *p, int *retreg)
c36e914d 157{
1f84f6b3 158 int i = 0, o;
159
160 *retreg = 0;
c36e914d 161
162 if (*p != '<')
163 return 0;
164
1f84f6b3 165 i++;
166 if (p[i] == '*') {
167 *retreg = 1;
168 i++;
169 }
170
171 for (o = 0; o < dlen; i++) {
c36e914d 172 if (p[i] == 0)
173 return 0;
174 if (p[i] == '>')
175 break;
176 dst[o++] = p[i];
177 }
178 dst[o] = 0;
179 return i + 1;
180}
181
182// hmh..
64c59faf 183static const char *known_type_mod[] = {
184 "const",
185 "signed",
186 "unsigned",
3ebea2cf 187 "enum",
840257f6 188 "CONST",
92804a48 189 "volatile",
64c59faf 190};
191
3ebea2cf 192static const char *known_ptr_types[] = {
da87ae38 193 "FARPROC",
92804a48 194 "WNDPROC",
bf2471e9 195 "LINECALLBACK",
e56ab892 196 "HACCEL",
c36e914d 197 "HANDLE",
e56ab892 198 "HBITMAP",
79af284c 199 "HBRUSH",
bf2471e9 200 "HCALL",
e56ab892 201 "HCURSOR",
3ebea2cf 202 "HDC",
a652aa9f 203 "HFONT",
3ebea2cf 204 "HGDIOBJ",
e56ab892 205 "HGLOBAL",
79af284c 206 "HHOOK",
da87ae38 207 "HICON",
e56ab892 208 "HINSTANCE",
c7ed83dd 209 "HIMC", // DWORD in mingw, ptr in wine..
bf2471e9 210 "HLINE",
211 "HLINEAPP",
212 "HLOCAL",
e56ab892 213 "HMODULE",
da87ae38 214 "HPALETTE",
e56ab892 215 "HRGN",
216 "HRSRC",
217 "HKEY",
218 "HMENU",
7aca4698 219 "HWAVEOUT",
e56ab892 220 "HWND",
b62264bc 221 "PAPPBARDATA",
ef6b315d 222 "PBYTE",
a2c1d768 223 "PCRITICAL_SECTION",
b62264bc 224 "PDEVMODEA",
3ebea2cf 225 "PDWORD",
92804a48 226 "PFILETIME",
bf2471e9 227 "PLARGE_INTEGER",
79af284c 228 "PHANDLE",
94d447fb 229 "PHKEY",
230 "PLONG",
a2c1d768 231 "PMEMORY_BASIC_INFORMATION",
46411e6c 232 "PUINT",
f9327ad4 233 "PULARGE_INTEGER",
234 "PULONG_PTR",
3ebea2cf 235 "PVOID",
236 "PCVOID",
ef6b315d 237 "PWORD",
79af284c 238 "REFCLSID",
ead38b9e 239 "REFGUID",
79af284c 240 "REFIID",
241 "HOOKPROC",
e56ab892 242 "DLGPROC",
cdfaeed7 243 "TIMERPROC",
244 "WNDENUMPROC",
4f12f671 245 "va_list",
246 "__VALIST",
3ebea2cf 247};
248
249static const char *ignored_keywords[] = {
250 "extern",
251 "WINBASEAPI",
252 "WINUSERAPI",
4f12f671 253 "WINGDIAPI",
254 "WINADVAPI",
c36e914d 255};
256
3ebea2cf 257static int typecmp(const char *n, const char *t)
39b168b8 258{
259 for (; *t != 0; n++, t++) {
260 while (n[0] == ' ' && (n[1] == ' ' || n[1] == '*'))
261 n++;
262 while (t[0] == ' ' && (t[1] == ' ' || t[1] == '*'))
263 t++;
264 if (*n != *t)
3ebea2cf 265 return *n - *t;
39b168b8 266 }
267
3ebea2cf 268 return 0;
39b168b8 269}
270
3ebea2cf 271static const char *skip_type_mod(const char *n)
c36e914d 272{
64c59faf 273 int len;
39b168b8 274 int i;
c36e914d 275
64c59faf 276 for (i = 0; i < ARRAY_SIZE(known_type_mod); i++) {
277 len = strlen(known_type_mod[i]);
278 if (strncmp(n, known_type_mod[i], len) != 0)
279 continue;
bd96f656 280 if (!my_isblank(n[len]))
281 continue;
64c59faf 282
283 n += len;
284 while (my_isblank(*n))
285 n++;
286 i = 0;
287 }
288
3ebea2cf 289 return n;
290}
291
292static int check_type(const char *name, struct parsed_type *type)
293{
294 const char *n, *n1;
295 int ret = -1;
296 int i;
297
298 n = skip_type_mod(name);
299
865f1aca 300 if (!strncmp(n, "struct", 6) && my_isblank(n[6])) {
301 type->is_struct = 1;
302
303 n += 6;
304 while (my_isblank(*n))
305 n++;
306 }
307
3ebea2cf 308 for (i = 0; i < ARRAY_SIZE(known_ptr_types); i++) {
309 if (typecmp(n, known_ptr_types[i]))
64c59faf 310 continue;
311
3ebea2cf 312 type->is_ptr = 1;
313 break;
c36e914d 314 }
315
a652aa9f 316 if (n[0] == 'L' && n[1] == 'P' && strncmp(n, "LPARAM", 6))
3ebea2cf 317 type->is_ptr = 1;
318
319 // assume single word
320 while (!my_isblank(*n) && !my_issep(*n))
321 n++;
322
323 while (1) {
324 n1 = n;
325 while (my_isblank(*n))
326 n++;
327 if (*n == '*') {
328 type->is_ptr = 1;
329 n++;
330 continue;
331 }
332 break;
333 }
334
335 ret = n1 - name;
336 type->name = strndup(name, ret);
5f70a34f 337 if (IS(type->name, "__VALIST") || IS(type->name, "va_list"))
338 type->is_va_list = 1;
a2c1d768 339 if (IS(type->name, "VOID"))
340 memcpy(type->name, "void", 4);
341
3ebea2cf 342 return ret;
c36e914d 343}
344
345/* args are always expanded to 32bit */
346static const char *map_reg(const char *reg)
347{
348 const char *regs_f[] = { "eax", "ebx", "ecx", "edx", "esi", "edi" };
349 const char *regs_w[] = { "ax", "bx", "cx", "dx", "si", "di" };
350 const char *regs_b[] = { "al", "bl", "cl", "dl" };
351 int i;
352
353 for (i = 0; i < ARRAY_SIZE(regs_w); i++)
354 if (IS(reg, regs_w[i]))
355 return regs_f[i];
356
357 for (i = 0; i < ARRAY_SIZE(regs_b); i++)
358 if (IS(reg, regs_b[i]))
359 return regs_f[i];
360
361 return reg;
362}
363
a652aa9f 364static int check_struct_arg(struct parsed_proto_arg *arg)
365{
366 if (IS(arg->type.name, "POINT"))
367 return 2 - 1;
368
369 return 0;
370}
371
93b5bd18 372static int parse_protostr(char *protostr, struct parsed_proto *pp);
373
374static int parse_arg(char **p_, struct parsed_proto_arg *arg, int xarg)
375{
376 char buf[256];
377 char *p = *p_;
378 char *pe;
379 int ret;
380
381 arg->pp = calloc(1, sizeof(*arg->pp));
382 my_assert_not(arg->pp, NULL);
383 arg->pp->is_arg = 1;
384
385 pe = p;
386 while (1) {
387 pe = strpbrk(pe, ",()");
388 if (pe == NULL)
389 return -1;
390 if (*pe == ',' || *pe == ')')
391 break;
392 pe = strchr(pe, ')');
393 if (pe == NULL)
394 return -1;
395 pe++;
396 }
397
398 if (pe - p > sizeof(buf) - 1)
399 return -1;
400 memcpy(buf, p, pe - p);
401 buf[pe - p] = 0;
402
403 ret = parse_protostr(buf, arg->pp);
404 if (ret < 0)
405 return -1;
406
1fe8d40e 407 if (IS_START(arg->pp->name, "guess"))
408 arg->pp->is_guessed = 1;
409
93b5bd18 410 // we don't use actual names right now...
411 snprintf(arg->pp->name, sizeof(arg->pp->name), "a%d", xarg);
412
413 if (!arg->type.is_struct)
414 // we'll treat it as void * for non-calls
415 arg->type.name = strdup("void *");
416 arg->type.is_ptr = 1;
417
418 p += ret;
419 *p_ = p;
420 return 0;
421}
422
c36e914d 423static int parse_protostr(char *protostr, struct parsed_proto *pp)
424{
39b168b8 425 struct parsed_proto_arg *arg;
c36e914d 426 char regparm[16];
427 char buf[256];
428 char cconv[32];
1f84f6b3 429 int is_retreg;
39b168b8 430 char *p, *p1;
93b5bd18 431 int xarg = 0;
3ebea2cf 432 int i, l;
c36e914d 433 int ret;
c36e914d 434
06c5d854 435 p = sskip(protostr);
c36e914d 436 if (p[0] == '/' && p[1] == '/') {
06c5d854 437 printf("%s:%d: commented out?\n", hdrfn, hdrfline);
c36e914d 438 p = sskip(p + 2);
439 }
440
865f1aca 441 // allow start of line comment
442 if (p[0] == '/' && p[1] == '*') {
443 p = strstr(p + 2, "*/");
444 if (p == NULL) {
445 printf("%s:%d: multiline comments unsupported\n",
446 hdrfn, hdrfline);
447 return -1;
448 }
449 p = sskip(p + 2);
450 }
451
452 // we need remaining hints in comments, so strip / *
06c5d854 453 for (p1 = p; p1[0] != 0 && p1[1] != 0; p1++) {
454 if ((p1[0] == '/' && p1[1] == '*')
455 || (p1[0] == '*' && p1[1] == '/'))
456 p1[0] = p1[1] = ' ';
457 }
458
e56ab892 459 if (!strncmp(p, "DECLSPEC_NORETURN ", 18)) {
460 pp->is_noreturn = 1;
461 p = sskip(p + 18);
462 }
463
3ebea2cf 464 for (i = 0; i < ARRAY_SIZE(ignored_keywords); i++) {
465 l = strlen(ignored_keywords[i]);
466 if (!strncmp(p, ignored_keywords[i], l) && my_isblank(p[l]))
467 p = sskip(p + l + 1);
468 }
06c5d854 469
1fe8d40e 470 if (IS_START(p, "DECL_IMPORT ")) {
471 pp->is_import = 1;
472 p = sskip(p + 12);
473 }
474
3ebea2cf 475 ret = check_type(p, &pp->ret_type);
476 if (ret <= 0) {
63df67be 477 printf("%s:%d:%zd: unhandled return in '%s'\n",
c36e914d 478 hdrfn, hdrfline, (p - protostr) + 1, protostr);
39b168b8 479 return -1;
c36e914d 480 }
64c59faf 481 p = sskip(p + ret);
c36e914d 482
da87ae38 483 if (!strncmp(p, "noreturn ", 9)) {
484 pp->is_noreturn = 1;
485 p = sskip(p + 9);
486 }
487
06c5d854 488 if (!strchr(p, ')')) {
489 p = next_idt(buf, sizeof(buf), p);
490 p = sskip(p);
93b5bd18 491 if (!pp->is_arg && buf[0] == 0) {
492 printf("%s:%d:%zd: var name is missing\n",
06c5d854 493 hdrfn, hdrfline, (p - protostr) + 1);
494 return -1;
495 }
496 strcpy(pp->name, buf);
497
498 p1 = strchr(p, ']');
499 if (p1 != NULL) {
500 p = p1 + 1;
3ebea2cf 501 pp->ret_type.is_array = 1;
06c5d854 502 }
503 return p - protostr;
504 }
505
506 pp->is_func = 1;
507
39b168b8 508 if (*p == '(') {
509 pp->is_fptr = 1;
510 p = sskip(p + 1);
511 }
512
c36e914d 513 p = next_word(cconv, sizeof(cconv), p);
514 p = sskip(p);
515 if (cconv[0] == 0) {
63df67be 516 printf("%s:%d:%zd: cconv missing\n",
c36e914d 517 hdrfn, hdrfline, (p - protostr) + 1);
39b168b8 518 return -1;
c36e914d 519 }
520 if (IS(cconv, "__cdecl"))
521 pp->is_stdcall = 0;
522 else if (IS(cconv, "__stdcall"))
523 pp->is_stdcall = 1;
c0050df6 524 else if (IS(cconv, "__fastcall")) {
525 pp->is_fastcall = 1;
526 pp->is_stdcall = 1; // sort of..
527 }
c36e914d 528 else if (IS(cconv, "__thiscall"))
529 pp->is_stdcall = 1;
530 else if (IS(cconv, "__userpurge"))
de50b98b 531 pp->is_stdcall = 1; // IDA
c36e914d 532 else if (IS(cconv, "__usercall"))
de50b98b 533 pp->is_stdcall = 0; // IDA
1f84f6b3 534 else if (IS(cconv, "__userstack")) {
535 pp->is_stdcall = 0; // custom
536 pp->is_userstack = 1;
537 }
79af284c 538 else if (IS(cconv, "WINAPI") || IS(cconv, "PASCAL"))
64c59faf 539 pp->is_stdcall = 1;
c36e914d 540 else {
63df67be 541 printf("%s:%d:%zd: unhandled cconv: '%s'\n",
c36e914d 542 hdrfn, hdrfline, (p - protostr) + 1, cconv);
39b168b8 543 return -1;
544 }
545
546 if (pp->is_fptr) {
547 if (*p != '*') {
63df67be 548 printf("%s:%d:%zd: '*' expected\n",
39b168b8 549 hdrfn, hdrfline, (p - protostr) + 1);
550 return -1;
551 }
bd96f656 552 p++;
553 // XXX: skipping extra asterisks, for now
554 while (*p == '*')
555 p++;
556 p = sskip(p);
c36e914d 557 }
558
559 p = next_idt(buf, sizeof(buf), p);
560 p = sskip(p);
561 if (buf[0] == 0) {
de50b98b 562 //printf("%s:%d:%zd: func name missing\n",
563 // hdrfn, hdrfline, (p - protostr) + 1);
564 //return -1;
c36e914d 565 }
39b168b8 566 strcpy(pp->name, buf);
c36e914d 567
1f84f6b3 568 ret = get_regparm(regparm, sizeof(regparm), p, &is_retreg);
c36e914d 569 if (ret > 0) {
570 if (!IS(regparm, "eax") && !IS(regparm, "ax")
2b43685d 571 && !IS(regparm, "al") && !IS(regparm, "edx:eax"))
c36e914d 572 {
63df67be 573 printf("%s:%d:%zd: bad regparm: %s\n",
c36e914d 574 hdrfn, hdrfline, (p - protostr) + 1, regparm);
39b168b8 575 return -1;
c36e914d 576 }
577 p += ret;
578 p = sskip(p);
579 }
580
39b168b8 581 if (pp->is_fptr) {
bd96f656 582 if (*p == '[') {
583 // not really ret_type is array, but ohwell
584 pp->ret_type.is_array = 1;
585 p = strchr(p + 1, ']');
586 if (p == NULL) {
587 printf("%s:%d:%zd: ']' expected\n",
588 hdrfn, hdrfline, (p - protostr) + 1);
589 return -1;
590 }
591 p = sskip(p + 1);
592 }
39b168b8 593 if (*p != ')') {
63df67be 594 printf("%s:%d:%zd: ')' expected\n",
39b168b8 595 hdrfn, hdrfline, (p - protostr) + 1);
596 return -1;
597 }
598 p = sskip(p + 1);
599 }
600
c36e914d 601 if (*p != '(') {
63df67be 602 printf("%s:%d:%zd: '(' expected, got '%c'\n",
c36e914d 603 hdrfn, hdrfline, (p - protostr) + 1, *p);
39b168b8 604 return -1;
c36e914d 605 }
606 p++;
607
39b168b8 608 // check for x(void)
609 p = sskip(p);
06c5d854 610 if ((!strncmp(p, "void", 4) || !strncmp(p, "VOID", 4))
611 && *sskip(p + 4) == ')')
39b168b8 612 p += 4;
613
c36e914d 614 while (1) {
615 p = sskip(p);
39b168b8 616 if (*p == ')') {
617 p++;
c36e914d 618 break;
39b168b8 619 }
840257f6 620 if (xarg > 0) {
621 if (*p != ',') {
622 printf("%s:%d:%zd: ',' expected\n",
623 hdrfn, hdrfline, (p - protostr) + 1);
624 return -1;
625 }
c36e914d 626 p = sskip(p + 1);
840257f6 627 }
c36e914d 628
7ba45c34 629 if (!strncmp(p, "...", 3)) {
630 pp->is_vararg = 1;
631 p = sskip(p + 3);
632 if (*p == ')') {
633 p++;
634 break;
635 }
63df67be 636 printf("%s:%d:%zd: ')' expected\n",
7ba45c34 637 hdrfn, hdrfline, (p - protostr) + 1);
638 return -1;
639 }
640
39b168b8 641 arg = &pp->arg[xarg];
c36e914d 642 xarg++;
643
39b168b8 644 p1 = p;
3ebea2cf 645 ret = check_type(p, &arg->type);
646 if (ret <= 0) {
63df67be 647 printf("%s:%d:%zd: unhandled type for arg%d\n",
c36e914d 648 hdrfn, hdrfline, (p - protostr) + 1, xarg);
39b168b8 649 return -1;
c36e914d 650 }
64c59faf 651 p = sskip(p + ret);
c36e914d 652
93b5bd18 653 if (*p == '(' || arg->type.is_struct) {
654 // func ptr or struct
655 ret = parse_arg(&p1, arg, xarg);
39b168b8 656 if (ret < 0) {
63df67be 657 printf("%s:%d:%zd: funcarg parse failed\n",
39b168b8 658 hdrfn, hdrfline, p1 - protostr);
659 return -1;
660 }
93b5bd18 661 p = p1;
39b168b8 662 }
663
c36e914d 664 p = next_idt(buf, sizeof(buf), p);
665 p = sskip(p);
666#if 0
667 if (buf[0] == 0) {
63df67be 668 printf("%s:%d:%zd: idt missing for arg%d\n",
c36e914d 669 hdrfn, hdrfline, (p - protostr) + 1, xarg);
39b168b8 670 return -1;
c36e914d 671 }
672#endif
39b168b8 673 arg->reg = NULL;
c36e914d 674
1f84f6b3 675 ret = get_regparm(regparm, sizeof(regparm), p, &is_retreg);
c36e914d 676 if (ret > 0) {
677 p += ret;
678 p = sskip(p);
679
39b168b8 680 arg->reg = strdup(map_reg(regparm));
1f84f6b3 681 arg->type.is_retreg = is_retreg;
682 pp->has_retreg |= is_retreg;
c36e914d 683 }
a652aa9f 684
b62264bc 685 if (IS(arg->type.name, "float")
686 || IS(arg->type.name, "double"))
687 {
688 arg->type.is_float = 1;
689 }
690
f9327ad4 691 if (!arg->type.is_ptr && (strstr(arg->type.name, "int64")
692 || IS(arg->type.name, "double")))
7e50b291 693 {
2c31fb4c 694 arg->type.is_64bit = 1;
7e50b291 695 // hack..
7e50b291 696 pp_copy_arg(&pp->arg[xarg], arg);
2c31fb4c 697 arg = &pp->arg[xarg];
7e50b291 698 xarg++;
2c31fb4c 699 free(arg->type.name);
700 arg->type.name = strdup("dummy");
7e50b291 701 }
702
a652aa9f 703 ret = check_struct_arg(arg);
704 if (ret > 0) {
705 pp->has_structarg = 1;
706 arg->type.is_struct = 1;
707 free(arg->type.name);
708 arg->type.name = strdup("int");
709 for (l = 0; l < ret; l++) {
710 pp_copy_arg(&pp->arg[xarg], arg);
711 xarg++;
712 }
713 }
c36e914d 714 }
715
716 if (xarg > 0 && (IS(cconv, "__fastcall") || IS(cconv, "__thiscall"))) {
717 if (pp->arg[0].reg != NULL) {
718 printf("%s:%d: %s with arg1 spec %s?\n",
719 hdrfn, hdrfline, cconv, pp->arg[0].reg);
720 }
721 pp->arg[0].reg = strdup("ecx");
722 }
723
724 if (xarg > 1 && IS(cconv, "__fastcall")) {
725 if (pp->arg[1].reg != NULL) {
726 printf("%s:%d: %s with arg2 spec %s?\n",
727 hdrfn, hdrfline, cconv, pp->arg[1].reg);
728 }
729 pp->arg[1].reg = strdup("edx");
730 }
731
732 pp->argc = xarg;
733
734 for (i = 0; i < pp->argc; i++) {
735 if (pp->arg[i].reg == NULL)
736 pp->argc_stack++;
737 else
738 pp->argc_reg++;
739 }
740
c0050df6 741 if (pp->argc == 1 && pp->arg[0].reg != NULL
742 && IS(pp->arg[0].reg, "ecx"))
743 {
744 pp->is_fastcall = 1;
745 }
746 else if (pp->argc_reg == 2
747 && pp->arg[0].reg != NULL && IS(pp->arg[0].reg, "ecx")
748 && pp->arg[1].reg != NULL && IS(pp->arg[1].reg, "edx"))
749 {
750 pp->is_fastcall = 1;
751 }
752
753 if (pp->is_vararg && (pp->is_stdcall || pp->is_fastcall)) {
754 printf("%s:%d: vararg %s?\n", hdrfn, hdrfline, cconv);
755 return -1;
756 }
757
39b168b8 758 return p - protostr;
c36e914d 759}
760
bd96f656 761static int pp_name_cmp(const void *p1, const void *p2)
762{
763 const struct parsed_proto *pp1 = p1, *pp2 = p2;
764 return strcmp(pp1->name, pp2->name);
765}
766
865f1aca 767static int ps_name_cmp(const void *p1, const void *p2)
768{
769 const struct parsed_struct *ps1 = p1, *ps2 = p2;
770 return strcmp(ps1->name, ps2->name);
771}
772
773// parsed struct cache
774static struct parsed_struct *ps_cache;
775static int ps_cache_size;
776static int ps_cache_alloc;
777
778static int struct_handler(FILE *fhdr, char *proto, int *line)
779{
780 struct parsed_struct *ps;
781 char lstr[256], *p;
782 int offset = 0;
783 int m = 0;
784 int ret;
785
786 if (ps_cache_size >= ps_cache_alloc) {
787 ps_cache_alloc = ps_cache_alloc * 2 + 64;
788 ps_cache = realloc(ps_cache, ps_cache_alloc
789 * sizeof(ps_cache[0]));
790 my_assert_not(ps_cache, NULL);
791 memset(ps_cache + ps_cache_size, 0,
792 (ps_cache_alloc - ps_cache_size)
793 * sizeof(ps_cache[0]));
794 }
795
796 ps = &ps_cache[ps_cache_size++];
797 ret = sscanf(proto, "struct %255s {", ps->name);
798 if (ret != 1) {
799 printf("%s:%d: struct parse failed\n", hdrfn, *line);
800 return -1;
801 }
802
803 while (fgets(lstr, sizeof(lstr), fhdr))
804 {
805 (*line)++;
806
807 p = sskip(lstr);
808 if (p[0] == '/' && p[1] == '/')
809 continue;
810 if (p[0] == '}')
811 break;
812
813 if (m >= ARRAY_SIZE(ps->members)) {
814 printf("%s:%d: too many struct members\n",
815 hdrfn, *line);
816 return -1;
817 }
818
819 hdrfline = *line;
820 ret = parse_protostr(p, &ps->members[m].pp);
821 if (ret < 0) {
822 printf("%s:%d: struct member #%d/%02x "
823 "doesn't parse\n", hdrfn, *line,
824 m, offset);
825 return -1;
826 }
827 ps->members[m].offset = offset;
828 offset += 4;
829 m++;
830 }
831
832 ps->member_count = m;
833
834 return 0;
835}
836
837// parsed proto cache
bd96f656 838static struct parsed_proto *pp_cache;
839static int pp_cache_size;
840static int pp_cache_alloc;
841
61e29183 842static int b_pp_c_handler(char *proto, const char *fname,
ebc4dc43 843 int is_include, int is_osinc, int is_cinc)
bd96f656 844{
845 int ret;
846
847 if (pp_cache_size >= pp_cache_alloc) {
848 pp_cache_alloc = pp_cache_alloc * 2 + 64;
849 pp_cache = realloc(pp_cache, pp_cache_alloc
850 * sizeof(pp_cache[0]));
851 my_assert_not(pp_cache, NULL);
852 memset(pp_cache + pp_cache_size, 0,
853 (pp_cache_alloc - pp_cache_size)
854 * sizeof(pp_cache[0]));
855 }
856
857 ret = parse_protostr(proto, &pp_cache[pp_cache_size]);
858 if (ret < 0)
859 return -1;
860
61e29183 861 pp_cache[pp_cache_size].is_include = is_include;
862 pp_cache[pp_cache_size].is_osinc = is_osinc;
ebc4dc43 863 pp_cache[pp_cache_size].is_cinc = is_cinc;
bd96f656 864 pp_cache_size++;
865 return 0;
866}
867
865f1aca 868static void build_caches(FILE *fhdr)
c36e914d 869{
1f906263 870 long pos;
c36e914d 871 int ret;
872
1f906263 873 pos = ftell(fhdr);
bd96f656 874 rewind(fhdr);
875
61e29183 876 ret = do_protostrs(fhdr, hdrfn, 0);
bd96f656 877 if (ret < 0)
878 exit(1);
879
880 qsort(pp_cache, pp_cache_size, sizeof(pp_cache[0]), pp_name_cmp);
865f1aca 881 qsort(ps_cache, ps_cache_size, sizeof(ps_cache[0]), ps_name_cmp);
1f906263 882 fseek(fhdr, pos, SEEK_SET);
bd96f656 883}
884
36595fd2 885static const struct parsed_proto *proto_parse(FILE *fhdr, const char *sym,
886 int quiet)
bd96f656 887{
888 const struct parsed_proto *pp_ret;
889 struct parsed_proto pp_search;
7aca4698 890 char *p;
bd96f656 891
892 if (pp_cache == NULL)
865f1aca 893 build_caches(fhdr);
bd96f656 894
f9327ad4 895 // ugh...
896 if (sym[0] == '_' && !IS_START(sym, "__W"))
bd96f656 897 sym++;
c36e914d 898
bd96f656 899 strcpy(pp_search.name, sym);
7aca4698 900 p = strchr(pp_search.name, '@');
901 if (p != NULL)
902 *p = 0;
903
bd96f656 904 pp_ret = bsearch(&pp_search, pp_cache, pp_cache_size,
905 sizeof(pp_cache[0]), pp_name_cmp);
36595fd2 906 if (pp_ret == NULL && !quiet)
c36e914d 907 printf("%s: sym '%s' is missing\n", hdrfn, sym);
bd96f656 908
909 return pp_ret;
910}
911
865f1aca 912static const struct parsed_proto *proto_lookup_struct(FILE *fhdr,
913 const char *type, int offset)
914{
915 struct parsed_struct ps_search, *ps;
916 int m;
917
918 if (pp_cache == NULL)
919 build_caches(fhdr);
920 if (ps_cache_size == 0)
921 return NULL;
922
923 while (my_isblank(*type))
924 type++;
925 if (!strncmp(type, "struct", 6) && my_isblank(type[6]))
926 type += 7;
927
928 if (sscanf(type, "%255s", ps_search.name) != 1)
929 return NULL;
930
931 ps = bsearch(&ps_search, ps_cache, ps_cache_size,
932 sizeof(ps_cache[0]), ps_name_cmp);
933 if (ps == NULL) {
934 printf("%s: struct '%s' is missing\n",
935 hdrfn, ps_search.name);
936 return NULL;
937 }
938
939 for (m = 0; m < ps->member_count; m++) {
940 if (ps->members[m].offset == offset)
941 return &ps->members[m].pp;
942 }
943
944 return NULL;
945}
946
a652aa9f 947static void pp_copy_arg(struct parsed_proto_arg *d,
948 const struct parsed_proto_arg *s)
949{
950 memcpy(d, s, sizeof(*d));
951
952 if (s->reg != NULL) {
953 d->reg = strdup(s->reg);
954 my_assert_not(d->reg, NULL);
955 }
956 if (s->type.name != NULL) {
957 d->type.name = strdup(s->type.name);
958 my_assert_not(d->type.name, NULL);
959 }
93b5bd18 960 if (s->pp != NULL) {
961 d->pp = malloc(sizeof(*d->pp));
962 my_assert_not(d->pp, NULL);
963 memcpy(d->pp, s->pp, sizeof(*d->pp));
a652aa9f 964 }
965}
966
bd96f656 967struct parsed_proto *proto_clone(const struct parsed_proto *pp_c)
968{
969 struct parsed_proto *pp;
970 int i;
971
972 pp = malloc(sizeof(*pp));
973 my_assert_not(pp, NULL);
974 memcpy(pp, pp_c, sizeof(*pp)); // lazy..
975
976 // do the actual deep copy..
a652aa9f 977 for (i = 0; i < pp_c->argc; i++)
978 pp_copy_arg(&pp->arg[i], &pp_c->arg[i]);
bd96f656 979 if (pp_c->ret_type.name != NULL)
980 pp->ret_type.name = strdup(pp_c->ret_type.name);
c36e914d 981
bd96f656 982 return pp;
c36e914d 983}
984
27ebfaed 985
986static inline int pp_cmp_func(const struct parsed_proto *pp1,
987 const struct parsed_proto *pp2)
988{
989 int i;
990
991 if (pp1->argc != pp2->argc || pp1->argc_reg != pp2->argc_reg)
992 return 1;
993 else {
994 for (i = 0; i < pp1->argc; i++) {
995 if ((pp1->arg[i].reg != NULL) != (pp2->arg[i].reg != NULL))
996 return 1;
997
998 if ((pp1->arg[i].reg != NULL)
999 && !IS(pp1->arg[i].reg, pp2->arg[i].reg))
1000 {
1001 return 1;
1002 }
1003 }
1004 }
1005
1006 return 0;
1007}
1008
b74c31e3 1009static inline void pp_print(char *buf, size_t buf_size,
1010 const struct parsed_proto *pp)
1011{
1012 size_t l;
1013 int i;
1014
1015 snprintf(buf, buf_size, "%s %s(", pp->ret_type.name, pp->name);
1016 l = strlen(buf);
1017
1018 for (i = 0; i < pp->argc_reg; i++) {
1019 snprintf(buf + l, buf_size - l, "%s%s",
1020 i == 0 ? "" : ", ", pp->arg[i].reg);
1021 l = strlen(buf);
1022 }
1023 if (pp->argc_stack > 0) {
1024 snprintf(buf + l, buf_size - l, "%s{%d stack}",
1025 i == 0 ? "" : ", ", pp->argc_stack);
1026 l = strlen(buf);
1027 }
1028 snprintf(buf + l, buf_size - l, ")");
1029}
1030
bd96f656 1031static inline void proto_release(struct parsed_proto *pp)
c36e914d 1032{
1033 int i;
1034
1035 for (i = 0; i < pp->argc; i++) {
39b168b8 1036 if (pp->arg[i].reg != NULL)
c36e914d 1037 free(pp->arg[i].reg);
3ebea2cf 1038 if (pp->arg[i].type.name != NULL)
1039 free(pp->arg[i].type.name);
93b5bd18 1040 if (pp->arg[i].pp != NULL)
1041 free(pp->arg[i].pp);
c36e914d 1042 }
3ebea2cf 1043 if (pp->ret_type.name != NULL)
1044 free(pp->ret_type.name);
bd96f656 1045 free(pp);
865f1aca 1046
1047 (void)proto_lookup_struct;
c36e914d 1048}