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