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