vararg funcs/calls, ebp- in ebp_frame, fixes
[ia32rtools.git] / tools / protoparse.h
CommitLineData
c36e914d 1
39b168b8 2struct parsed_proto;
3
3ebea2cf 4struct parsed_type {
5 char *name;
6 unsigned int is_array:1;
7 unsigned int is_ptr:1;
8};
9
39b168b8 10struct parsed_proto_arg {
11 char *reg;
3ebea2cf 12 struct parsed_type type;
39b168b8 13 struct parsed_proto *fptr;
14 void *datap;
15};
16
c36e914d 17struct parsed_proto {
39b168b8 18 char name[256];
3ebea2cf 19 union {
20 struct parsed_type ret_type;
21 struct parsed_type type;
22 };
39b168b8 23 struct parsed_proto_arg arg[16];
c36e914d 24 int argc;
25 int argc_stack;
26 int argc_reg;
06c5d854 27 unsigned int is_func:1;
39b168b8 28 unsigned int is_stdcall:1;
7ba45c34 29 unsigned int is_vararg:1;
39b168b8 30 unsigned int is_fptr:1;
c36e914d 31};
32
33static const char *hdrfn;
34static int hdrfline = 0;
35
39b168b8 36static int find_protostr(char *dst, size_t dlen, FILE *fhdr,
37 const char *fname, const char *sym_)
c36e914d 38{
39b168b8 39 const char *sym = sym_;
06c5d854 40 const char *finc_name;
39b168b8 41 FILE *finc;
42 int symlen;
c36e914d 43 int line = 0;
39b168b8 44 int ret;
c36e914d 45 char *p;
46
39b168b8 47 if (sym[0] == '_' && strncmp(fname, "stdc", 4) == 0)
48 sym++;
49 symlen = strlen(sym);
50
c36e914d 51 rewind(fhdr);
52
53 while (fgets(dst, dlen, fhdr))
54 {
55 line++;
06c5d854 56 if (strncmp(dst, "//#include ", 11) == 0) {
57 finc_name = dst + 11;
58 p = strpbrk(finc_name, "\r\n ");
39b168b8 59 if (p != NULL)
60 *p = 0;
61
06c5d854 62 finc = fopen(finc_name, "r");
39b168b8 63 if (finc == NULL) {
64 printf("%s:%d: can't open '%s'\n",
06c5d854 65 fname, line, finc_name);
39b168b8 66 continue;
67 }
68 ret = find_protostr(dst, dlen, finc,
06c5d854 69 finc_name, sym_);
39b168b8 70 fclose(finc);
71 if (ret == 0)
72 break;
73 continue;
74 }
06c5d854 75 if (strncmp(sskip(dst), "//", 2) == 0)
76 continue;
39b168b8 77
78 p = strstr(dst, sym);
06c5d854 79 if (p != NULL && p > dst
80 && (my_isblank(p[-1]) || my_issep(p[-1]))
39b168b8 81 && (my_isblank(p[symlen]) || my_issep(p[symlen])))
c36e914d 82 break;
83 }
84 hdrfline = line;
85
86 if (feof(fhdr))
87 return -1;
88
89 p = dst + strlen(dst);
90 for (p--; p > dst && my_isblank(*p); --p)
91 *p = 0;
92
93 return 0;
94}
95
96static int get_regparm(char *dst, size_t dlen, char *p)
97{
98 int i, o;
99
100 if (*p != '<')
101 return 0;
102
103 for (o = 0, i = 1; o < dlen; i++) {
104 if (p[i] == 0)
105 return 0;
106 if (p[i] == '>')
107 break;
108 dst[o++] = p[i];
109 }
110 dst[o] = 0;
111 return i + 1;
112}
113
114// hmh..
64c59faf 115static const char *known_type_mod[] = {
116 "const",
117 "signed",
118 "unsigned",
3ebea2cf 119 "struct",
120 "enum",
64c59faf 121};
122
3ebea2cf 123static const char *known_ptr_types[] = {
c36e914d 124 "HANDLE",
3ebea2cf 125 "HMODULE",
126 "HINSTANCE",
c36e914d 127 "HWND",
3ebea2cf 128 "HDC",
129 "HGDIOBJ",
130 "PLONG",
131 "PDWORD",
132 "PVOID",
133 "PCVOID",
4f12f671 134 "va_list",
135 "__VALIST",
3ebea2cf 136};
137
138static const char *ignored_keywords[] = {
139 "extern",
140 "WINBASEAPI",
141 "WINUSERAPI",
4f12f671 142 "WINGDIAPI",
143 "WINADVAPI",
c36e914d 144};
145
64c59faf 146// returns ptr to char after type ends
3ebea2cf 147static int typecmp(const char *n, const char *t)
39b168b8 148{
149 for (; *t != 0; n++, t++) {
150 while (n[0] == ' ' && (n[1] == ' ' || n[1] == '*'))
151 n++;
152 while (t[0] == ' ' && (t[1] == ' ' || t[1] == '*'))
153 t++;
154 if (*n != *t)
3ebea2cf 155 return *n - *t;
39b168b8 156 }
157
3ebea2cf 158 return 0;
39b168b8 159}
160
3ebea2cf 161static const char *skip_type_mod(const char *n)
c36e914d 162{
64c59faf 163 int len;
39b168b8 164 int i;
c36e914d 165
64c59faf 166 for (i = 0; i < ARRAY_SIZE(known_type_mod); i++) {
167 len = strlen(known_type_mod[i]);
168 if (strncmp(n, known_type_mod[i], len) != 0)
169 continue;
170
171 n += len;
172 while (my_isblank(*n))
173 n++;
174 i = 0;
175 }
176
3ebea2cf 177 return n;
178}
179
180static int check_type(const char *name, struct parsed_type *type)
181{
182 const char *n, *n1;
183 int ret = -1;
184 int i;
185
186 n = skip_type_mod(name);
187
188 for (i = 0; i < ARRAY_SIZE(known_ptr_types); i++) {
189 if (typecmp(n, known_ptr_types[i]))
64c59faf 190 continue;
191
3ebea2cf 192 type->is_ptr = 1;
193 break;
c36e914d 194 }
195
3ebea2cf 196 if (n[0] == 'L' && n[1] == 'P')
197 type->is_ptr = 1;
198
199 // assume single word
200 while (!my_isblank(*n) && !my_issep(*n))
201 n++;
202
203 while (1) {
204 n1 = n;
205 while (my_isblank(*n))
206 n++;
207 if (*n == '*') {
208 type->is_ptr = 1;
209 n++;
210 continue;
211 }
212 break;
213 }
214
215 ret = n1 - name;
216 type->name = strndup(name, ret);
217 return ret;
c36e914d 218}
219
220/* args are always expanded to 32bit */
221static const char *map_reg(const char *reg)
222{
223 const char *regs_f[] = { "eax", "ebx", "ecx", "edx", "esi", "edi" };
224 const char *regs_w[] = { "ax", "bx", "cx", "dx", "si", "di" };
225 const char *regs_b[] = { "al", "bl", "cl", "dl" };
226 int i;
227
228 for (i = 0; i < ARRAY_SIZE(regs_w); i++)
229 if (IS(reg, regs_w[i]))
230 return regs_f[i];
231
232 for (i = 0; i < ARRAY_SIZE(regs_b); i++)
233 if (IS(reg, regs_b[i]))
234 return regs_f[i];
235
236 return reg;
237}
238
239static int parse_protostr(char *protostr, struct parsed_proto *pp)
240{
39b168b8 241 struct parsed_proto_arg *arg;
c36e914d 242 char regparm[16];
243 char buf[256];
244 char cconv[32];
c36e914d 245 int xarg = 0;
39b168b8 246 char *p, *p1;
3ebea2cf 247 int i, l;
c36e914d 248 int ret;
c36e914d 249
06c5d854 250 p = sskip(protostr);
c36e914d 251 if (p[0] == '/' && p[1] == '/') {
06c5d854 252 printf("%s:%d: commented out?\n", hdrfn, hdrfline);
c36e914d 253 p = sskip(p + 2);
254 }
255
06c5d854 256 // strip unneeded stuff
257 for (p1 = p; p1[0] != 0 && p1[1] != 0; p1++) {
258 if ((p1[0] == '/' && p1[1] == '*')
259 || (p1[0] == '*' && p1[1] == '/'))
260 p1[0] = p1[1] = ' ';
261 }
262
3ebea2cf 263 for (i = 0; i < ARRAY_SIZE(ignored_keywords); i++) {
264 l = strlen(ignored_keywords[i]);
265 if (!strncmp(p, ignored_keywords[i], l) && my_isblank(p[l]))
266 p = sskip(p + l + 1);
267 }
06c5d854 268
3ebea2cf 269 ret = check_type(p, &pp->ret_type);
270 if (ret <= 0) {
63df67be 271 printf("%s:%d:%zd: unhandled return in '%s'\n",
c36e914d 272 hdrfn, hdrfline, (p - protostr) + 1, protostr);
39b168b8 273 return -1;
c36e914d 274 }
64c59faf 275 p = sskip(p + ret);
c36e914d 276
06c5d854 277 if (!strchr(p, ')')) {
278 p = next_idt(buf, sizeof(buf), p);
279 p = sskip(p);
280 if (buf[0] == 0) {
63df67be 281 printf("%s:%d:%zd: var name missing\n",
06c5d854 282 hdrfn, hdrfline, (p - protostr) + 1);
283 return -1;
284 }
285 strcpy(pp->name, buf);
286
287 p1 = strchr(p, ']');
288 if (p1 != NULL) {
289 p = p1 + 1;
3ebea2cf 290 pp->ret_type.is_array = 1;
06c5d854 291 }
292 return p - protostr;
293 }
294
295 pp->is_func = 1;
296
39b168b8 297 if (*p == '(') {
298 pp->is_fptr = 1;
299 p = sskip(p + 1);
300 }
301
c36e914d 302 p = next_word(cconv, sizeof(cconv), p);
303 p = sskip(p);
304 if (cconv[0] == 0) {
63df67be 305 printf("%s:%d:%zd: cconv missing\n",
c36e914d 306 hdrfn, hdrfline, (p - protostr) + 1);
39b168b8 307 return -1;
c36e914d 308 }
309 if (IS(cconv, "__cdecl"))
310 pp->is_stdcall = 0;
311 else if (IS(cconv, "__stdcall"))
312 pp->is_stdcall = 1;
313 else if (IS(cconv, "__fastcall"))
314 pp->is_stdcall = 1;
315 else if (IS(cconv, "__thiscall"))
316 pp->is_stdcall = 1;
317 else if (IS(cconv, "__userpurge"))
318 pp->is_stdcall = 1; // in all cases seen..
319 else if (IS(cconv, "__usercall"))
320 pp->is_stdcall = 0; // ..or is it?
64c59faf 321 else if (IS(cconv, "WINAPI"))
322 pp->is_stdcall = 1;
c36e914d 323 else {
63df67be 324 printf("%s:%d:%zd: unhandled cconv: '%s'\n",
c36e914d 325 hdrfn, hdrfline, (p - protostr) + 1, cconv);
39b168b8 326 return -1;
327 }
328
329 if (pp->is_fptr) {
330 if (*p != '*') {
63df67be 331 printf("%s:%d:%zd: '*' expected\n",
39b168b8 332 hdrfn, hdrfline, (p - protostr) + 1);
333 return -1;
334 }
335 p = sskip(p + 1);
c36e914d 336 }
337
338 p = next_idt(buf, sizeof(buf), p);
339 p = sskip(p);
340 if (buf[0] == 0) {
63df67be 341 printf("%s:%d:%zd: func name missing\n",
39b168b8 342 hdrfn, hdrfline, (p - protostr) + 1);
343 return -1;
c36e914d 344 }
39b168b8 345 strcpy(pp->name, buf);
c36e914d 346
347 ret = get_regparm(regparm, sizeof(regparm), p);
348 if (ret > 0) {
349 if (!IS(regparm, "eax") && !IS(regparm, "ax")
350 && !IS(regparm, "al"))
351 {
63df67be 352 printf("%s:%d:%zd: bad regparm: %s\n",
c36e914d 353 hdrfn, hdrfline, (p - protostr) + 1, regparm);
39b168b8 354 return -1;
c36e914d 355 }
356 p += ret;
357 p = sskip(p);
358 }
359
39b168b8 360 if (pp->is_fptr) {
361 if (*p != ')') {
63df67be 362 printf("%s:%d:%zd: ')' expected\n",
39b168b8 363 hdrfn, hdrfline, (p - protostr) + 1);
364 return -1;
365 }
366 p = sskip(p + 1);
367 }
368
c36e914d 369 if (*p != '(') {
63df67be 370 printf("%s:%d:%zd: '(' expected, got '%c'\n",
c36e914d 371 hdrfn, hdrfline, (p - protostr) + 1, *p);
39b168b8 372 return -1;
c36e914d 373 }
374 p++;
375
39b168b8 376 // check for x(void)
377 p = sskip(p);
06c5d854 378 if ((!strncmp(p, "void", 4) || !strncmp(p, "VOID", 4))
379 && *sskip(p + 4) == ')')
39b168b8 380 p += 4;
381
c36e914d 382 while (1) {
383 p = sskip(p);
39b168b8 384 if (*p == ')') {
385 p++;
c36e914d 386 break;
39b168b8 387 }
c36e914d 388 if (*p == ',')
389 p = sskip(p + 1);
390
7ba45c34 391 if (!strncmp(p, "...", 3)) {
392 pp->is_vararg = 1;
393 p = sskip(p + 3);
394 if (*p == ')') {
395 p++;
396 break;
397 }
63df67be 398 printf("%s:%d:%zd: ')' expected\n",
7ba45c34 399 hdrfn, hdrfline, (p - protostr) + 1);
400 return -1;
401 }
402
39b168b8 403 arg = &pp->arg[xarg];
c36e914d 404 xarg++;
405
39b168b8 406 p1 = p;
3ebea2cf 407 ret = check_type(p, &arg->type);
408 if (ret <= 0) {
63df67be 409 printf("%s:%d:%zd: unhandled type for arg%d\n",
c36e914d 410 hdrfn, hdrfline, (p - protostr) + 1, xarg);
39b168b8 411 return -1;
c36e914d 412 }
64c59faf 413 p = sskip(p + ret);
c36e914d 414
39b168b8 415 if (*p == '(') {
416 // func ptr
417 arg->fptr = calloc(1, sizeof(*arg->fptr));
418 ret = parse_protostr(p1, arg->fptr);
419 if (ret < 0) {
63df67be 420 printf("%s:%d:%zd: funcarg parse failed\n",
39b168b8 421 hdrfn, hdrfline, p1 - protostr);
422 return -1;
423 }
424 // we'll treat it as void * for non-calls
3ebea2cf 425 arg->type.name = "void *";
426 arg->type.is_ptr = 1;
39b168b8 427
428 p = p1 + ret;
429 }
430
c36e914d 431 p = next_idt(buf, sizeof(buf), p);
432 p = sskip(p);
433#if 0
434 if (buf[0] == 0) {
63df67be 435 printf("%s:%d:%zd: idt missing for arg%d\n",
c36e914d 436 hdrfn, hdrfline, (p - protostr) + 1, xarg);
39b168b8 437 return -1;
c36e914d 438 }
439#endif
39b168b8 440 arg->reg = NULL;
c36e914d 441
442 ret = get_regparm(regparm, sizeof(regparm), p);
443 if (ret > 0) {
444 p += ret;
445 p = sskip(p);
446
39b168b8 447 arg->reg = strdup(map_reg(regparm));
c36e914d 448 }
449 }
450
451 if (xarg > 0 && (IS(cconv, "__fastcall") || IS(cconv, "__thiscall"))) {
452 if (pp->arg[0].reg != NULL) {
453 printf("%s:%d: %s with arg1 spec %s?\n",
454 hdrfn, hdrfline, cconv, pp->arg[0].reg);
455 }
456 pp->arg[0].reg = strdup("ecx");
457 }
458
459 if (xarg > 1 && IS(cconv, "__fastcall")) {
460 if (pp->arg[1].reg != NULL) {
461 printf("%s:%d: %s with arg2 spec %s?\n",
462 hdrfn, hdrfline, cconv, pp->arg[1].reg);
463 }
464 pp->arg[1].reg = strdup("edx");
465 }
466
7ba45c34 467 if (pp->is_vararg && pp->is_stdcall) {
468 printf("%s:%d: vararg stdcall?\n", hdrfn, hdrfline);
469 return -1;
470 }
471
c36e914d 472 pp->argc = xarg;
473
474 for (i = 0; i < pp->argc; i++) {
475 if (pp->arg[i].reg == NULL)
476 pp->argc_stack++;
477 else
478 pp->argc_reg++;
479 }
480
39b168b8 481 return p - protostr;
c36e914d 482}
483
484static int proto_parse(FILE *fhdr, const char *sym, struct parsed_proto *pp)
485{
486 char protostr[256];
487 int ret;
488
489 memset(pp, 0, sizeof(*pp));
490
39b168b8 491 ret = find_protostr(protostr, sizeof(protostr), fhdr, hdrfn, sym);
c36e914d 492 if (ret != 0) {
493 printf("%s: sym '%s' is missing\n", hdrfn, sym);
494 return ret;
495 }
496
39b168b8 497 return parse_protostr(protostr, pp) < 0 ? -1 : 0;
c36e914d 498}
499
500static void proto_release(struct parsed_proto *pp)
501{
502 int i;
503
504 for (i = 0; i < pp->argc; i++) {
39b168b8 505 if (pp->arg[i].reg != NULL)
c36e914d 506 free(pp->arg[i].reg);
3ebea2cf 507 if (pp->arg[i].type.name != NULL)
508 free(pp->arg[i].type.name);
39b168b8 509 if (pp->arg[i].fptr != NULL)
510 free(pp->arg[i].fptr);
c36e914d 511 }
3ebea2cf 512 if (pp->ret_type.name != NULL)
513 free(pp->ret_type.name);
c36e914d 514}