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