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