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