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