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