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