minor fixes, winsvc api
[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",
383dff16 219 "HMONITOR",
7aca4698 220 "HWAVEOUT",
e56ab892 221 "HWND",
b62264bc 222 "PAPPBARDATA",
ef6b315d 223 "PBYTE",
a2c1d768 224 "PCRITICAL_SECTION",
b62264bc 225 "PDEVMODEA",
3ebea2cf 226 "PDWORD",
92804a48 227 "PFILETIME",
bf2471e9 228 "PLARGE_INTEGER",
79af284c 229 "PHANDLE",
94d447fb 230 "PHKEY",
231 "PLONG",
a2c1d768 232 "PMEMORY_BASIC_INFORMATION",
46411e6c 233 "PUINT",
f9327ad4 234 "PULARGE_INTEGER",
235 "PULONG_PTR",
3ebea2cf 236 "PVOID",
237 "PCVOID",
ef6b315d 238 "PWORD",
79af284c 239 "REFCLSID",
ead38b9e 240 "REFGUID",
79af284c 241 "REFIID",
354f5504 242 "SC_HANDLE",
243 "SERVICE_STATUS_HANDLE",
79af284c 244 "HOOKPROC",
e56ab892 245 "DLGPROC",
cdfaeed7 246 "TIMERPROC",
247 "WNDENUMPROC",
4f12f671 248 "va_list",
249 "__VALIST",
3ebea2cf 250};
251
252static const char *ignored_keywords[] = {
253 "extern",
254 "WINBASEAPI",
255 "WINUSERAPI",
4f12f671 256 "WINGDIAPI",
257 "WINADVAPI",
c36e914d 258};
259
3ebea2cf 260static int typecmp(const char *n, const char *t)
39b168b8 261{
262 for (; *t != 0; n++, t++) {
263 while (n[0] == ' ' && (n[1] == ' ' || n[1] == '*'))
264 n++;
265 while (t[0] == ' ' && (t[1] == ' ' || t[1] == '*'))
266 t++;
267 if (*n != *t)
3ebea2cf 268 return *n - *t;
39b168b8 269 }
270
3ebea2cf 271 return 0;
39b168b8 272}
273
3ebea2cf 274static const char *skip_type_mod(const char *n)
c36e914d 275{
64c59faf 276 int len;
39b168b8 277 int i;
c36e914d 278
64c59faf 279 for (i = 0; i < ARRAY_SIZE(known_type_mod); i++) {
280 len = strlen(known_type_mod[i]);
281 if (strncmp(n, known_type_mod[i], len) != 0)
282 continue;
bd96f656 283 if (!my_isblank(n[len]))
284 continue;
64c59faf 285
286 n += len;
287 while (my_isblank(*n))
288 n++;
289 i = 0;
290 }
291
3ebea2cf 292 return n;
293}
294
295static int check_type(const char *name, struct parsed_type *type)
296{
297 const char *n, *n1;
298 int ret = -1;
299 int i;
300
301 n = skip_type_mod(name);
302
865f1aca 303 if (!strncmp(n, "struct", 6) && my_isblank(n[6])) {
304 type->is_struct = 1;
305
306 n += 6;
307 while (my_isblank(*n))
308 n++;
309 }
310
3ebea2cf 311 for (i = 0; i < ARRAY_SIZE(known_ptr_types); i++) {
312 if (typecmp(n, known_ptr_types[i]))
64c59faf 313 continue;
314
3ebea2cf 315 type->is_ptr = 1;
316 break;
c36e914d 317 }
318
a652aa9f 319 if (n[0] == 'L' && n[1] == 'P' && strncmp(n, "LPARAM", 6))
3ebea2cf 320 type->is_ptr = 1;
321
322 // assume single word
323 while (!my_isblank(*n) && !my_issep(*n))
324 n++;
325
326 while (1) {
327 n1 = n;
328 while (my_isblank(*n))
329 n++;
330 if (*n == '*') {
331 type->is_ptr = 1;
332 n++;
333 continue;
334 }
335 break;
336 }
337
338 ret = n1 - name;
339 type->name = strndup(name, ret);
5f70a34f 340 if (IS(type->name, "__VALIST") || IS(type->name, "va_list"))
341 type->is_va_list = 1;
a2c1d768 342 if (IS(type->name, "VOID"))
343 memcpy(type->name, "void", 4);
344
3ebea2cf 345 return ret;
c36e914d 346}
347
348/* args are always expanded to 32bit */
349static const char *map_reg(const char *reg)
350{
351 const char *regs_f[] = { "eax", "ebx", "ecx", "edx", "esi", "edi" };
352 const char *regs_w[] = { "ax", "bx", "cx", "dx", "si", "di" };
353 const char *regs_b[] = { "al", "bl", "cl", "dl" };
354 int i;
355
356 for (i = 0; i < ARRAY_SIZE(regs_w); i++)
357 if (IS(reg, regs_w[i]))
358 return regs_f[i];
359
360 for (i = 0; i < ARRAY_SIZE(regs_b); i++)
361 if (IS(reg, regs_b[i]))
362 return regs_f[i];
363
364 return reg;
365}
366
a652aa9f 367static int check_struct_arg(struct parsed_proto_arg *arg)
368{
369 if (IS(arg->type.name, "POINT"))
370 return 2 - 1;
371
372 return 0;
373}
374
93b5bd18 375static int parse_protostr(char *protostr, struct parsed_proto *pp);
376
377static int parse_arg(char **p_, struct parsed_proto_arg *arg, int xarg)
378{
379 char buf[256];
380 char *p = *p_;
381 char *pe;
382 int ret;
383
384 arg->pp = calloc(1, sizeof(*arg->pp));
385 my_assert_not(arg->pp, NULL);
386 arg->pp->is_arg = 1;
387
388 pe = p;
389 while (1) {
390 pe = strpbrk(pe, ",()");
391 if (pe == NULL)
392 return -1;
393 if (*pe == ',' || *pe == ')')
394 break;
395 pe = strchr(pe, ')');
396 if (pe == NULL)
397 return -1;
398 pe++;
399 }
400
401 if (pe - p > sizeof(buf) - 1)
402 return -1;
403 memcpy(buf, p, pe - p);
404 buf[pe - p] = 0;
405
406 ret = parse_protostr(buf, arg->pp);
407 if (ret < 0)
408 return -1;
409
1fe8d40e 410 if (IS_START(arg->pp->name, "guess"))
411 arg->pp->is_guessed = 1;
412
93b5bd18 413 // we don't use actual names right now...
414 snprintf(arg->pp->name, sizeof(arg->pp->name), "a%d", xarg);
415
416 if (!arg->type.is_struct)
417 // we'll treat it as void * for non-calls
418 arg->type.name = strdup("void *");
419 arg->type.is_ptr = 1;
420
421 p += ret;
422 *p_ = p;
423 return 0;
424}
425
c36e914d 426static int parse_protostr(char *protostr, struct parsed_proto *pp)
427{
39b168b8 428 struct parsed_proto_arg *arg;
c36e914d 429 char regparm[16];
430 char buf[256];
431 char cconv[32];
1f84f6b3 432 int is_retreg;
39b168b8 433 char *p, *p1;
93b5bd18 434 int xarg = 0;
3ebea2cf 435 int i, l;
c36e914d 436 int ret;
c36e914d 437
06c5d854 438 p = sskip(protostr);
c36e914d 439 if (p[0] == '/' && p[1] == '/') {
06c5d854 440 printf("%s:%d: commented out?\n", hdrfn, hdrfline);
c36e914d 441 p = sskip(p + 2);
442 }
443
865f1aca 444 // allow start of line comment
445 if (p[0] == '/' && p[1] == '*') {
446 p = strstr(p + 2, "*/");
447 if (p == NULL) {
448 printf("%s:%d: multiline comments unsupported\n",
449 hdrfn, hdrfline);
450 return -1;
451 }
452 p = sskip(p + 2);
453 }
454
455 // we need remaining hints in comments, so strip / *
06c5d854 456 for (p1 = p; p1[0] != 0 && p1[1] != 0; p1++) {
457 if ((p1[0] == '/' && p1[1] == '*')
458 || (p1[0] == '*' && p1[1] == '/'))
459 p1[0] = p1[1] = ' ';
460 }
461
e56ab892 462 if (!strncmp(p, "DECLSPEC_NORETURN ", 18)) {
463 pp->is_noreturn = 1;
464 p = sskip(p + 18);
465 }
466
3ebea2cf 467 for (i = 0; i < ARRAY_SIZE(ignored_keywords); i++) {
468 l = strlen(ignored_keywords[i]);
469 if (!strncmp(p, ignored_keywords[i], l) && my_isblank(p[l]))
470 p = sskip(p + l + 1);
471 }
06c5d854 472
1fe8d40e 473 if (IS_START(p, "DECL_IMPORT ")) {
474 pp->is_import = 1;
475 p = sskip(p + 12);
476 }
477
3ebea2cf 478 ret = check_type(p, &pp->ret_type);
479 if (ret <= 0) {
63df67be 480 printf("%s:%d:%zd: unhandled return in '%s'\n",
c36e914d 481 hdrfn, hdrfline, (p - protostr) + 1, protostr);
39b168b8 482 return -1;
c36e914d 483 }
64c59faf 484 p = sskip(p + ret);
c36e914d 485
da87ae38 486 if (!strncmp(p, "noreturn ", 9)) {
487 pp->is_noreturn = 1;
488 p = sskip(p + 9);
489 }
490
06c5d854 491 if (!strchr(p, ')')) {
492 p = next_idt(buf, sizeof(buf), p);
493 p = sskip(p);
93b5bd18 494 if (!pp->is_arg && buf[0] == 0) {
495 printf("%s:%d:%zd: var name is missing\n",
06c5d854 496 hdrfn, hdrfline, (p - protostr) + 1);
497 return -1;
498 }
499 strcpy(pp->name, buf);
500
501 p1 = strchr(p, ']');
502 if (p1 != NULL) {
503 p = p1 + 1;
3ebea2cf 504 pp->ret_type.is_array = 1;
06c5d854 505 }
506 return p - protostr;
507 }
508
509 pp->is_func = 1;
510
39b168b8 511 if (*p == '(') {
512 pp->is_fptr = 1;
513 p = sskip(p + 1);
514 }
515
c36e914d 516 p = next_word(cconv, sizeof(cconv), p);
517 p = sskip(p);
518 if (cconv[0] == 0) {
63df67be 519 printf("%s:%d:%zd: cconv missing\n",
c36e914d 520 hdrfn, hdrfline, (p - protostr) + 1);
39b168b8 521 return -1;
c36e914d 522 }
523 if (IS(cconv, "__cdecl"))
524 pp->is_stdcall = 0;
525 else if (IS(cconv, "__stdcall"))
526 pp->is_stdcall = 1;
c0050df6 527 else if (IS(cconv, "__fastcall")) {
528 pp->is_fastcall = 1;
529 pp->is_stdcall = 1; // sort of..
530 }
c36e914d 531 else if (IS(cconv, "__thiscall"))
532 pp->is_stdcall = 1;
533 else if (IS(cconv, "__userpurge"))
de50b98b 534 pp->is_stdcall = 1; // IDA
c36e914d 535 else if (IS(cconv, "__usercall"))
de50b98b 536 pp->is_stdcall = 0; // IDA
1f84f6b3 537 else if (IS(cconv, "__userstack")) {
538 pp->is_stdcall = 0; // custom
539 pp->is_userstack = 1;
540 }
79af284c 541 else if (IS(cconv, "WINAPI") || IS(cconv, "PASCAL"))
64c59faf 542 pp->is_stdcall = 1;
c36e914d 543 else {
63df67be 544 printf("%s:%d:%zd: unhandled cconv: '%s'\n",
c36e914d 545 hdrfn, hdrfline, (p - protostr) + 1, cconv);
39b168b8 546 return -1;
547 }
548
549 if (pp->is_fptr) {
550 if (*p != '*') {
63df67be 551 printf("%s:%d:%zd: '*' expected\n",
39b168b8 552 hdrfn, hdrfline, (p - protostr) + 1);
553 return -1;
554 }
bd96f656 555 p++;
556 // XXX: skipping extra asterisks, for now
557 while (*p == '*')
558 p++;
559 p = sskip(p);
c36e914d 560 }
561
562 p = next_idt(buf, sizeof(buf), p);
563 p = sskip(p);
564 if (buf[0] == 0) {
de50b98b 565 //printf("%s:%d:%zd: func name missing\n",
566 // hdrfn, hdrfline, (p - protostr) + 1);
567 //return -1;
c36e914d 568 }
39b168b8 569 strcpy(pp->name, buf);
c36e914d 570
1f84f6b3 571 ret = get_regparm(regparm, sizeof(regparm), p, &is_retreg);
c36e914d 572 if (ret > 0) {
573 if (!IS(regparm, "eax") && !IS(regparm, "ax")
2b43685d 574 && !IS(regparm, "al") && !IS(regparm, "edx:eax"))
c36e914d 575 {
63df67be 576 printf("%s:%d:%zd: bad regparm: %s\n",
c36e914d 577 hdrfn, hdrfline, (p - protostr) + 1, regparm);
39b168b8 578 return -1;
c36e914d 579 }
580 p += ret;
581 p = sskip(p);
582 }
583
39b168b8 584 if (pp->is_fptr) {
bd96f656 585 if (*p == '[') {
586 // not really ret_type is array, but ohwell
587 pp->ret_type.is_array = 1;
588 p = strchr(p + 1, ']');
589 if (p == NULL) {
590 printf("%s:%d:%zd: ']' expected\n",
591 hdrfn, hdrfline, (p - protostr) + 1);
592 return -1;
593 }
594 p = sskip(p + 1);
595 }
39b168b8 596 if (*p != ')') {
63df67be 597 printf("%s:%d:%zd: ')' expected\n",
39b168b8 598 hdrfn, hdrfline, (p - protostr) + 1);
599 return -1;
600 }
601 p = sskip(p + 1);
602 }
603
c36e914d 604 if (*p != '(') {
63df67be 605 printf("%s:%d:%zd: '(' expected, got '%c'\n",
c36e914d 606 hdrfn, hdrfline, (p - protostr) + 1, *p);
39b168b8 607 return -1;
c36e914d 608 }
609 p++;
610
39b168b8 611 // check for x(void)
612 p = sskip(p);
06c5d854 613 if ((!strncmp(p, "void", 4) || !strncmp(p, "VOID", 4))
614 && *sskip(p + 4) == ')')
39b168b8 615 p += 4;
616
c36e914d 617 while (1) {
618 p = sskip(p);
39b168b8 619 if (*p == ')') {
620 p++;
c36e914d 621 break;
39b168b8 622 }
840257f6 623 if (xarg > 0) {
624 if (*p != ',') {
625 printf("%s:%d:%zd: ',' expected\n",
626 hdrfn, hdrfline, (p - protostr) + 1);
627 return -1;
628 }
c36e914d 629 p = sskip(p + 1);
840257f6 630 }
c36e914d 631
7ba45c34 632 if (!strncmp(p, "...", 3)) {
633 pp->is_vararg = 1;
634 p = sskip(p + 3);
635 if (*p == ')') {
636 p++;
637 break;
638 }
63df67be 639 printf("%s:%d:%zd: ')' expected\n",
7ba45c34 640 hdrfn, hdrfline, (p - protostr) + 1);
641 return -1;
642 }
643
39b168b8 644 arg = &pp->arg[xarg];
c36e914d 645 xarg++;
646
39b168b8 647 p1 = p;
3ebea2cf 648 ret = check_type(p, &arg->type);
649 if (ret <= 0) {
63df67be 650 printf("%s:%d:%zd: unhandled type for arg%d\n",
c36e914d 651 hdrfn, hdrfline, (p - protostr) + 1, xarg);
39b168b8 652 return -1;
c36e914d 653 }
64c59faf 654 p = sskip(p + ret);
c36e914d 655
93b5bd18 656 if (*p == '(' || arg->type.is_struct) {
657 // func ptr or struct
658 ret = parse_arg(&p1, arg, xarg);
39b168b8 659 if (ret < 0) {
63df67be 660 printf("%s:%d:%zd: funcarg parse failed\n",
39b168b8 661 hdrfn, hdrfline, p1 - protostr);
662 return -1;
663 }
93b5bd18 664 p = p1;
39b168b8 665 }
666
c36e914d 667 p = next_idt(buf, sizeof(buf), p);
668 p = sskip(p);
669#if 0
670 if (buf[0] == 0) {
63df67be 671 printf("%s:%d:%zd: idt missing for arg%d\n",
c36e914d 672 hdrfn, hdrfline, (p - protostr) + 1, xarg);
39b168b8 673 return -1;
c36e914d 674 }
675#endif
39b168b8 676 arg->reg = NULL;
c36e914d 677
1f84f6b3 678 ret = get_regparm(regparm, sizeof(regparm), p, &is_retreg);
c36e914d 679 if (ret > 0) {
680 p += ret;
681 p = sskip(p);
682
39b168b8 683 arg->reg = strdup(map_reg(regparm));
1f84f6b3 684 arg->type.is_retreg = is_retreg;
685 pp->has_retreg |= is_retreg;
c36e914d 686 }
a652aa9f 687
b62264bc 688 if (IS(arg->type.name, "float")
689 || IS(arg->type.name, "double"))
690 {
691 arg->type.is_float = 1;
692 }
693
f9327ad4 694 if (!arg->type.is_ptr && (strstr(arg->type.name, "int64")
695 || IS(arg->type.name, "double")))
7e50b291 696 {
2c31fb4c 697 arg->type.is_64bit = 1;
7e50b291 698 // hack..
7e50b291 699 pp_copy_arg(&pp->arg[xarg], arg);
2c31fb4c 700 arg = &pp->arg[xarg];
7e50b291 701 xarg++;
2c31fb4c 702 free(arg->type.name);
703 arg->type.name = strdup("dummy");
7e50b291 704 }
705
a652aa9f 706 ret = check_struct_arg(arg);
707 if (ret > 0) {
708 pp->has_structarg = 1;
709 arg->type.is_struct = 1;
710 free(arg->type.name);
711 arg->type.name = strdup("int");
712 for (l = 0; l < ret; l++) {
713 pp_copy_arg(&pp->arg[xarg], arg);
714 xarg++;
715 }
716 }
c36e914d 717 }
718
719 if (xarg > 0 && (IS(cconv, "__fastcall") || IS(cconv, "__thiscall"))) {
720 if (pp->arg[0].reg != NULL) {
721 printf("%s:%d: %s with arg1 spec %s?\n",
722 hdrfn, hdrfline, cconv, pp->arg[0].reg);
723 }
724 pp->arg[0].reg = strdup("ecx");
725 }
726
727 if (xarg > 1 && IS(cconv, "__fastcall")) {
728 if (pp->arg[1].reg != NULL) {
729 printf("%s:%d: %s with arg2 spec %s?\n",
730 hdrfn, hdrfline, cconv, pp->arg[1].reg);
731 }
732 pp->arg[1].reg = strdup("edx");
733 }
734
735 pp->argc = xarg;
736
737 for (i = 0; i < pp->argc; i++) {
738 if (pp->arg[i].reg == NULL)
739 pp->argc_stack++;
740 else
741 pp->argc_reg++;
742 }
743
c0050df6 744 if (pp->argc == 1 && pp->arg[0].reg != NULL
745 && IS(pp->arg[0].reg, "ecx"))
746 {
747 pp->is_fastcall = 1;
748 }
749 else if (pp->argc_reg == 2
750 && pp->arg[0].reg != NULL && IS(pp->arg[0].reg, "ecx")
751 && pp->arg[1].reg != NULL && IS(pp->arg[1].reg, "edx"))
752 {
753 pp->is_fastcall = 1;
754 }
755
756 if (pp->is_vararg && (pp->is_stdcall || pp->is_fastcall)) {
757 printf("%s:%d: vararg %s?\n", hdrfn, hdrfline, cconv);
758 return -1;
759 }
760
39b168b8 761 return p - protostr;
c36e914d 762}
763
bd96f656 764static int pp_name_cmp(const void *p1, const void *p2)
765{
766 const struct parsed_proto *pp1 = p1, *pp2 = p2;
767 return strcmp(pp1->name, pp2->name);
768}
769
865f1aca 770static int ps_name_cmp(const void *p1, const void *p2)
771{
772 const struct parsed_struct *ps1 = p1, *ps2 = p2;
773 return strcmp(ps1->name, ps2->name);
774}
775
776// parsed struct cache
777static struct parsed_struct *ps_cache;
778static int ps_cache_size;
779static int ps_cache_alloc;
780
781static int struct_handler(FILE *fhdr, char *proto, int *line)
782{
783 struct parsed_struct *ps;
784 char lstr[256], *p;
785 int offset = 0;
786 int m = 0;
787 int ret;
788
789 if (ps_cache_size >= ps_cache_alloc) {
790 ps_cache_alloc = ps_cache_alloc * 2 + 64;
791 ps_cache = realloc(ps_cache, ps_cache_alloc
792 * sizeof(ps_cache[0]));
793 my_assert_not(ps_cache, NULL);
794 memset(ps_cache + ps_cache_size, 0,
795 (ps_cache_alloc - ps_cache_size)
796 * sizeof(ps_cache[0]));
797 }
798
799 ps = &ps_cache[ps_cache_size++];
800 ret = sscanf(proto, "struct %255s {", ps->name);
801 if (ret != 1) {
802 printf("%s:%d: struct parse failed\n", hdrfn, *line);
803 return -1;
804 }
805
806 while (fgets(lstr, sizeof(lstr), fhdr))
807 {
808 (*line)++;
809
810 p = sskip(lstr);
811 if (p[0] == '/' && p[1] == '/')
812 continue;
813 if (p[0] == '}')
814 break;
815
816 if (m >= ARRAY_SIZE(ps->members)) {
817 printf("%s:%d: too many struct members\n",
818 hdrfn, *line);
819 return -1;
820 }
821
822 hdrfline = *line;
823 ret = parse_protostr(p, &ps->members[m].pp);
824 if (ret < 0) {
825 printf("%s:%d: struct member #%d/%02x "
826 "doesn't parse\n", hdrfn, *line,
827 m, offset);
828 return -1;
829 }
830 ps->members[m].offset = offset;
831 offset += 4;
832 m++;
833 }
834
835 ps->member_count = m;
836
837 return 0;
838}
839
840// parsed proto cache
bd96f656 841static struct parsed_proto *pp_cache;
842static int pp_cache_size;
843static int pp_cache_alloc;
844
61e29183 845static int b_pp_c_handler(char *proto, const char *fname,
ebc4dc43 846 int is_include, int is_osinc, int is_cinc)
bd96f656 847{
848 int ret;
849
850 if (pp_cache_size >= pp_cache_alloc) {
851 pp_cache_alloc = pp_cache_alloc * 2 + 64;
852 pp_cache = realloc(pp_cache, pp_cache_alloc
853 * sizeof(pp_cache[0]));
854 my_assert_not(pp_cache, NULL);
855 memset(pp_cache + pp_cache_size, 0,
856 (pp_cache_alloc - pp_cache_size)
857 * sizeof(pp_cache[0]));
858 }
859
860 ret = parse_protostr(proto, &pp_cache[pp_cache_size]);
861 if (ret < 0)
862 return -1;
863
61e29183 864 pp_cache[pp_cache_size].is_include = is_include;
865 pp_cache[pp_cache_size].is_osinc = is_osinc;
ebc4dc43 866 pp_cache[pp_cache_size].is_cinc = is_cinc;
bd96f656 867 pp_cache_size++;
868 return 0;
869}
870
865f1aca 871static void build_caches(FILE *fhdr)
c36e914d 872{
1f906263 873 long pos;
c36e914d 874 int ret;
875
1f906263 876 pos = ftell(fhdr);
bd96f656 877 rewind(fhdr);
878
61e29183 879 ret = do_protostrs(fhdr, hdrfn, 0);
bd96f656 880 if (ret < 0)
881 exit(1);
882
883 qsort(pp_cache, pp_cache_size, sizeof(pp_cache[0]), pp_name_cmp);
865f1aca 884 qsort(ps_cache, ps_cache_size, sizeof(ps_cache[0]), ps_name_cmp);
1f906263 885 fseek(fhdr, pos, SEEK_SET);
bd96f656 886}
887
36595fd2 888static const struct parsed_proto *proto_parse(FILE *fhdr, const char *sym,
889 int quiet)
bd96f656 890{
891 const struct parsed_proto *pp_ret;
892 struct parsed_proto pp_search;
7aca4698 893 char *p;
bd96f656 894
895 if (pp_cache == NULL)
865f1aca 896 build_caches(fhdr);
bd96f656 897
f9327ad4 898 // ugh...
899 if (sym[0] == '_' && !IS_START(sym, "__W"))
bd96f656 900 sym++;
c36e914d 901
bd96f656 902 strcpy(pp_search.name, sym);
7aca4698 903 p = strchr(pp_search.name, '@');
904 if (p != NULL)
905 *p = 0;
906
bd96f656 907 pp_ret = bsearch(&pp_search, pp_cache, pp_cache_size,
908 sizeof(pp_cache[0]), pp_name_cmp);
36595fd2 909 if (pp_ret == NULL && !quiet)
c36e914d 910 printf("%s: sym '%s' is missing\n", hdrfn, sym);
bd96f656 911
912 return pp_ret;
913}
914
865f1aca 915static const struct parsed_proto *proto_lookup_struct(FILE *fhdr,
916 const char *type, int offset)
917{
918 struct parsed_struct ps_search, *ps;
919 int m;
920
921 if (pp_cache == NULL)
922 build_caches(fhdr);
923 if (ps_cache_size == 0)
924 return NULL;
925
926 while (my_isblank(*type))
927 type++;
928 if (!strncmp(type, "struct", 6) && my_isblank(type[6]))
929 type += 7;
930
931 if (sscanf(type, "%255s", ps_search.name) != 1)
932 return NULL;
933
934 ps = bsearch(&ps_search, ps_cache, ps_cache_size,
935 sizeof(ps_cache[0]), ps_name_cmp);
936 if (ps == NULL) {
937 printf("%s: struct '%s' is missing\n",
938 hdrfn, ps_search.name);
939 return NULL;
940 }
941
942 for (m = 0; m < ps->member_count; m++) {
943 if (ps->members[m].offset == offset)
944 return &ps->members[m].pp;
945 }
946
947 return NULL;
948}
949
a652aa9f 950static void pp_copy_arg(struct parsed_proto_arg *d,
951 const struct parsed_proto_arg *s)
952{
953 memcpy(d, s, sizeof(*d));
954
955 if (s->reg != NULL) {
956 d->reg = strdup(s->reg);
957 my_assert_not(d->reg, NULL);
958 }
959 if (s->type.name != NULL) {
960 d->type.name = strdup(s->type.name);
961 my_assert_not(d->type.name, NULL);
962 }
93b5bd18 963 if (s->pp != NULL) {
964 d->pp = malloc(sizeof(*d->pp));
965 my_assert_not(d->pp, NULL);
966 memcpy(d->pp, s->pp, sizeof(*d->pp));
a652aa9f 967 }
968}
969
bd96f656 970struct parsed_proto *proto_clone(const struct parsed_proto *pp_c)
971{
972 struct parsed_proto *pp;
973 int i;
974
975 pp = malloc(sizeof(*pp));
976 my_assert_not(pp, NULL);
977 memcpy(pp, pp_c, sizeof(*pp)); // lazy..
978
979 // do the actual deep copy..
a652aa9f 980 for (i = 0; i < pp_c->argc; i++)
981 pp_copy_arg(&pp->arg[i], &pp_c->arg[i]);
bd96f656 982 if (pp_c->ret_type.name != NULL)
983 pp->ret_type.name = strdup(pp_c->ret_type.name);
c36e914d 984
bd96f656 985 return pp;
c36e914d 986}
987
27ebfaed 988
989static inline int pp_cmp_func(const struct parsed_proto *pp1,
990 const struct parsed_proto *pp2)
991{
992 int i;
993
994 if (pp1->argc != pp2->argc || pp1->argc_reg != pp2->argc_reg)
995 return 1;
996 else {
997 for (i = 0; i < pp1->argc; i++) {
998 if ((pp1->arg[i].reg != NULL) != (pp2->arg[i].reg != NULL))
999 return 1;
1000
1001 if ((pp1->arg[i].reg != NULL)
1002 && !IS(pp1->arg[i].reg, pp2->arg[i].reg))
1003 {
1004 return 1;
1005 }
1006 }
1007 }
1008
1009 return 0;
1010}
1011
b74c31e3 1012static inline void pp_print(char *buf, size_t buf_size,
1013 const struct parsed_proto *pp)
1014{
1015 size_t l;
1016 int i;
1017
1018 snprintf(buf, buf_size, "%s %s(", pp->ret_type.name, pp->name);
1019 l = strlen(buf);
1020
1021 for (i = 0; i < pp->argc_reg; i++) {
1022 snprintf(buf + l, buf_size - l, "%s%s",
1023 i == 0 ? "" : ", ", pp->arg[i].reg);
1024 l = strlen(buf);
1025 }
1026 if (pp->argc_stack > 0) {
1027 snprintf(buf + l, buf_size - l, "%s{%d stack}",
1028 i == 0 ? "" : ", ", pp->argc_stack);
1029 l = strlen(buf);
1030 }
1031 snprintf(buf + l, buf_size - l, ")");
1032}
1033
bd96f656 1034static inline void proto_release(struct parsed_proto *pp)
c36e914d 1035{
1036 int i;
1037
1038 for (i = 0; i < pp->argc; i++) {
39b168b8 1039 if (pp->arg[i].reg != NULL)
c36e914d 1040 free(pp->arg[i].reg);
3ebea2cf 1041 if (pp->arg[i].type.name != NULL)
1042 free(pp->arg[i].type.name);
93b5bd18 1043 if (pp->arg[i].pp != NULL)
1044 free(pp->arg[i].pp);
c36e914d 1045 }
3ebea2cf 1046 if (pp->ret_type.name != NULL)
1047 free(pp->ret_type.name);
bd96f656 1048 free(pp);
865f1aca 1049
1050 (void)proto_lookup_struct;
c36e914d 1051}