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