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