fix edx arg-reg corruption in fromasm
[ia32rtools.git] / tools / protoparse.h
1
2 struct parsed_proto {
3         struct {
4                 char *reg;
5                 const char *type;
6                 void *datap;
7         } arg[16];
8         const char *ret_type;
9         int is_stdcall;
10         int argc;
11         int argc_stack;
12         int argc_reg;
13 };
14
15 static const char *hdrfn;
16 static int hdrfline = 0;
17
18 static int find_protostr(char *dst, size_t dlen, FILE *fhdr, const char *sym)
19 {
20         int line = 0;
21         char *p;
22
23         rewind(fhdr);
24
25         while (fgets(dst, dlen, fhdr))
26         {
27                 line++;
28                 if (strstr(dst, sym) != NULL)
29                         break;
30         }
31         hdrfline = line;
32
33         if (feof(fhdr))
34                 return -1;
35
36         p = dst + strlen(dst);
37         for (p--; p > dst && my_isblank(*p); --p)
38                 *p = 0;
39
40         return 0;
41 }
42
43 static int get_regparm(char *dst, size_t dlen, char *p)
44 {
45         int i, o;
46
47         if (*p != '<')
48                 return 0;
49
50         for (o = 0, i = 1; o < dlen; i++) {
51                 if (p[i] == 0)
52                         return 0;
53                 if (p[i] == '>')
54                         break;
55                 dst[o++] = p[i];
56         }
57         dst[o] = 0;
58         return i + 1;
59 }
60
61 // hmh..
62 static const char *known_types[] = {
63         "const void *",
64         "void *",
65         "char *",
66         "FILE *",
67         "int *",
68         "unsigned __int8",
69         "unsigned __int16",
70         "unsigned int",
71         "signed int",
72         "char",
73         "__int8",
74         "__int16",
75         "int",
76         "bool",
77         "void",
78         "BYTE",
79         "WORD",
80         "DWORD",
81         "_DWORD",
82         "HMODULE",
83         "HANDLE",
84         "HWND",
85         "LPCSTR",
86         "size_t",
87 };
88
89 static const char *check_type(const char *name)
90 {
91         int i, l;
92
93         for (i = 0; i < ARRAY_SIZE(known_types); i++) {
94                 l = strlen(known_types[i]);
95                 if (strncmp(known_types[i], name, l) == 0)
96                         return known_types[i];
97         }
98
99         return NULL;
100 }
101
102 /* args are always expanded to 32bit */
103 static const char *map_reg(const char *reg)
104 {
105         const char *regs_f[] = { "eax", "ebx", "ecx", "edx", "esi", "edi" };
106         const char *regs_w[] = { "ax",  "bx",  "cx",  "dx",  "si",  "di" };
107         const char *regs_b[] = { "al",  "bl",  "cl",  "dl" };
108         int i;
109
110         for (i = 0; i < ARRAY_SIZE(regs_w); i++)
111                 if (IS(reg, regs_w[i]))
112                         return regs_f[i];
113
114         for (i = 0; i < ARRAY_SIZE(regs_b); i++)
115                 if (IS(reg, regs_b[i]))
116                         return regs_f[i];
117
118         return reg;
119 }
120
121 static int parse_protostr(char *protostr, struct parsed_proto *pp)
122 {
123         char regparm[16];
124         char buf[256];
125         char cconv[32];
126         const char *kt;
127         int xarg = 0;
128         int ret;
129         char *p;
130         int i;
131
132         p = protostr;
133         if (p[0] == '/' && p[1] == '/') {
134                 //printf("warning: decl for sym '%s' is commented out\n", sym);
135                 p = sskip(p + 2);
136         }
137
138         kt = check_type(p);
139         if (kt == NULL) {
140                 printf("%s:%d:%ld: unhandled return in '%s'\n",
141                         hdrfn, hdrfline, (p - protostr) + 1, protostr);
142                 return 1;
143         }
144         pp->ret_type = kt;
145         p += strlen(kt);
146         p = sskip(p);
147
148         p = next_word(cconv, sizeof(cconv), p);
149         p = sskip(p);
150         if (cconv[0] == 0) {
151                 printf("%s:%d:%ld: cconv missing\n",
152                         hdrfn, hdrfline, (p - protostr) + 1);
153                 return 1;
154         }
155         if      (IS(cconv, "__cdecl"))
156                 pp->is_stdcall = 0;
157         else if (IS(cconv, "__stdcall"))
158                 pp->is_stdcall = 1;
159         else if (IS(cconv, "__fastcall"))
160                 pp->is_stdcall = 1;
161         else if (IS(cconv, "__thiscall"))
162                 pp->is_stdcall = 1;
163         else if (IS(cconv, "__userpurge"))
164                 pp->is_stdcall = 1; // in all cases seen..
165         else if (IS(cconv, "__usercall"))
166                 pp->is_stdcall = 0; // ..or is it?
167         else {
168                 printf("%s:%d:%ld: unhandled cconv: '%s'\n",
169                         hdrfn, hdrfline, (p - protostr) + 1, cconv);
170                 return 1;
171         }
172
173         p = next_idt(buf, sizeof(buf), p);
174         p = sskip(p);
175         if (buf[0] == 0) {
176                 printf("%s:%d:%ld: func name missing\n",
177                                 hdrfn, hdrfline, (p - protostr) + 1);
178                 return 1;
179         }
180
181         ret = get_regparm(regparm, sizeof(regparm), p);
182         if (ret > 0) {
183                 if (!IS(regparm, "eax") && !IS(regparm, "ax")
184                  && !IS(regparm, "al"))
185                 {
186                         printf("%s:%d:%ld: bad regparm: %s\n",
187                                 hdrfn, hdrfline, (p - protostr) + 1, regparm);
188                         return 1;
189                 }
190                 p += ret;
191                 p = sskip(p);
192         }
193
194         if (*p != '(') {
195                 printf("%s:%d:%ld: '(' expected, got '%c'\n",
196                                 hdrfn, hdrfline, (p - protostr) + 1, *p);
197                 return 1;
198         }
199         p++;
200
201         while (1) {
202                 p = sskip(p);
203                 if (*p == ')')
204                         break;
205                 if (*p == ',')
206                         p = sskip(p + 1);
207
208                 xarg++;
209
210                 kt = check_type(p);
211                 if (kt == NULL) {
212                         printf("%s:%d:%ld: unhandled type for arg%d\n",
213                                 hdrfn, hdrfline, (p - protostr) + 1, xarg);
214                         return 1;
215                 }
216                 pp->arg[xarg - 1].type = kt;
217                 p += strlen(kt);
218                 p = sskip(p);
219
220                 p = next_idt(buf, sizeof(buf), p);
221                 p = sskip(p);
222 #if 0
223                 if (buf[0] == 0) {
224                         printf("%s:%d:%ld: idt missing for arg%d\n",
225                                 hdrfn, hdrfline, (p - protostr) + 1, xarg);
226                         return 1;
227                 }
228 #endif
229                 pp->arg[xarg - 1].reg = NULL;
230
231                 ret = get_regparm(regparm, sizeof(regparm), p);
232                 if (ret > 0) {
233                         p += ret;
234                         p = sskip(p);
235
236                         pp->arg[xarg - 1].reg = strdup(map_reg(regparm));
237                 }
238         }
239
240         if (xarg > 0 && (IS(cconv, "__fastcall") || IS(cconv, "__thiscall"))) {
241                 if (pp->arg[0].reg != NULL) {
242                         printf("%s:%d: %s with arg1 spec %s?\n",
243                                 hdrfn, hdrfline, cconv, pp->arg[0].reg);
244                 }
245                 pp->arg[0].reg = strdup("ecx");
246         }
247
248         if (xarg > 1 && IS(cconv, "__fastcall")) {
249                 if (pp->arg[1].reg != NULL) {
250                         printf("%s:%d: %s with arg2 spec %s?\n",
251                                 hdrfn, hdrfline, cconv, pp->arg[1].reg);
252                 }
253                 pp->arg[1].reg = strdup("edx");
254         }
255
256         pp->argc = xarg;
257
258         for (i = 0; i < pp->argc; i++) {
259                 if (pp->arg[i].reg == NULL)
260                         pp->argc_stack++;
261                 else
262                         pp->argc_reg++;
263         }
264
265         return 0;
266 }
267
268 static int proto_parse(FILE *fhdr, const char *sym, struct parsed_proto *pp)
269 {
270         char protostr[256];
271         int ret;
272
273         memset(pp, 0, sizeof(*pp));
274
275         ret = find_protostr(protostr, sizeof(protostr), fhdr, sym);
276         if (ret != 0) {
277                 printf("%s: sym '%s' is missing\n", hdrfn, sym);
278                 return ret;
279         }
280
281         return parse_protostr(protostr, pp);
282 }
283
284 static void proto_release(struct parsed_proto *pp)
285 {
286         int i;
287
288         for (i = 0; i < pp->argc; i++) {
289                 if (pp->arg[i].reg == NULL)
290                         free(pp->arg[i].reg);
291         }
292 }