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