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