Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
wine-mirror
GitHub Repository: wine-mirror/wine
Path: blob/master/tools/winedump/search.c
4389 views
1
/*
2
* Prototype search and parsing functions
3
*
4
* Copyright 2000 Jon Griffiths
5
*
6
* This library is free software; you can redistribute it and/or
7
* modify it under the terms of the GNU Lesser General Public
8
* License as published by the Free Software Foundation; either
9
* version 2.1 of the License, or (at your option) any later version.
10
*
11
* This library is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14
* Lesser General Public License for more details.
15
*
16
* You should have received a copy of the GNU Lesser General Public
17
* License along with this library; if not, write to the Free Software
18
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19
*/
20
21
#include "config.h"
22
23
#include "winedump.h"
24
25
static char *grep_buff = NULL;
26
static char *fgrep_buff = NULL;
27
28
static BOOL symbol_from_prototype (parsed_symbol *sym, const char *prototype);
29
static const char *get_type (parsed_symbol *sym, const char *proto, int arg);
30
31
32
/*******************************************************************
33
* symbol_search
34
*
35
* Call Patrik Stridvall's 'function_grep.pl' script to retrieve a
36
* function prototype from include file(s)
37
*/
38
BOOL symbol_search (parsed_symbol *sym)
39
{
40
static const size_t MAX_RESULT_LEN = 1024;
41
FILE *grep;
42
int attempt = 0;
43
44
assert (globals.do_code);
45
assert (globals.directory);
46
assert (sym && sym->symbol);
47
48
if (!symbol_is_valid_c (sym))
49
return FALSE;
50
51
if (!grep_buff)
52
grep_buff = xmalloc (MAX_RESULT_LEN);
53
54
if (!fgrep_buff)
55
fgrep_buff = xmalloc (MAX_RESULT_LEN);
56
57
/* Use 'grep' to tell us which possible files the function is in,
58
* then use 'function_grep.pl' to get the prototype. If this fails the
59
* first time then give grep a more general query (that doesn't
60
* require an opening argument brace on the line with the function name).
61
*/
62
while (attempt < 2)
63
{
64
FILE *f_grep;
65
char *cmd = strmake( "grep -d recurse -l \"%s%s\" %s", sym->symbol,
66
!attempt ? "[[:blank:]]*(" : "", globals.directory);
67
68
if (VERBOSE)
69
puts (cmd);
70
71
fflush (NULL); /* See 'man popen' */
72
73
if (!(grep = popen (cmd, "r")))
74
fatal ("Cannot execute grep -l");
75
free (cmd);
76
77
while (fgets (grep_buff, MAX_RESULT_LEN, grep))
78
{
79
int i;
80
const char *extension = grep_buff;
81
for (i = 0; grep_buff[i] && grep_buff[i] != '\n' ; i++) {
82
if (grep_buff[i] == '.')
83
extension = &grep_buff[i];
84
}
85
grep_buff[i] = '\0';
86
87
/* Definitely not in these: */
88
if (strcmp(extension,".dll") == 0 ||
89
strcmp(extension,".lib") == 0 ||
90
strcmp(extension,".so") == 0 ||
91
strcmp(extension,".o") == 0)
92
continue;
93
94
if (VERBOSE)
95
puts (grep_buff);
96
97
cmd = strmake( "function_grep.pl %s \"%s\"", sym->symbol, grep_buff );
98
99
if (VERBOSE)
100
puts (cmd);
101
102
fflush (NULL); /* See 'man popen' */
103
104
if (!(f_grep = popen (cmd, "r")))
105
fatal ("Cannot execute function_grep.pl");
106
free (cmd);
107
108
while (fgets (grep_buff, MAX_RESULT_LEN, f_grep))
109
{
110
char *iter = grep_buff;
111
112
/* Keep only the first line */
113
symbol_clean_string(grep_buff);
114
115
for (i = 0; grep_buff[i] && grep_buff[i] != '\n' ; i++)
116
;
117
grep_buff[i] = '\0';
118
119
if (VERBOSE)
120
puts (grep_buff);
121
122
while ((iter = strstr (iter, sym->symbol)))
123
{
124
if (iter > grep_buff && (iter[-1] == ' ' || iter[-1] == '*') &&
125
(iter[strlen (sym->symbol)] == ' ' ||
126
iter[strlen (sym->symbol)] == '('))
127
{
128
if (VERBOSE)
129
printf ("Prototype '%s' looks OK, processing\n", grep_buff);
130
131
if (symbol_from_prototype (sym, grep_buff))
132
{
133
pclose (f_grep);
134
pclose (grep);
135
return TRUE; /* OK */
136
}
137
if (VERBOSE)
138
puts ("Failed, trying next");
139
}
140
else
141
iter += strlen (sym->symbol);
142
}
143
}
144
pclose (f_grep);
145
}
146
pclose (grep);
147
attempt++;
148
}
149
150
return FALSE; /* Not found */
151
}
152
153
154
/*******************************************************************
155
* symbol_from_prototype
156
*
157
* Convert a C prototype into a symbol
158
*/
159
static BOOL symbol_from_prototype (parsed_symbol *sym, const char *proto)
160
{
161
const char *iter;
162
BOOL found;
163
164
proto = get_type (sym, proto, -1); /* Get return type */
165
if (!proto)
166
return FALSE;
167
168
iter = str_match (proto, sym->symbol, &found);
169
170
if (!found)
171
{
172
char *call;
173
/* Calling Convention */
174
iter = strchr (iter, ' ');
175
if (!iter)
176
return FALSE;
177
178
call = str_substring (proto, iter);
179
180
if (!strcasecmp (call, "cdecl") || !strcasecmp (call, "__cdecl"))
181
sym->flags |= SYM_CDECL;
182
else
183
sym->flags |= SYM_STDCALL;
184
free (call);
185
iter = str_match (iter, sym->symbol, &found);
186
187
if (!found)
188
return FALSE;
189
190
if (VERBOSE)
191
printf ("Using %s calling convention\n",
192
sym->flags & SYM_CDECL ? "cdecl" : "stdcall");
193
}
194
else
195
sym->flags = CALLING_CONVENTION;
196
197
sym->function_name = xstrdup (sym->symbol);
198
proto = iter;
199
200
/* Now should be the arguments */
201
if (*proto++ != '(')
202
return FALSE;
203
204
for (; *proto == ' '; proto++);
205
206
if (!strncmp (proto, "void", 4))
207
return TRUE;
208
209
do
210
{
211
/* Process next argument */
212
str_match (proto, "...", &sym->varargs);
213
if (sym->varargs)
214
return TRUE;
215
216
if (!(proto = get_type (sym, proto, sym->argc)))
217
return FALSE;
218
219
sym->argc++;
220
221
if (*proto == ',')
222
proto++;
223
else if (*proto != ')')
224
return FALSE;
225
226
} while (*proto != ')');
227
228
return TRUE;
229
}
230
231
232
/*******************************************************************
233
* get_type
234
*
235
* Read a type from a prototype
236
*/
237
static const char *get_type (parsed_symbol *sym, const char *proto, int arg)
238
{
239
BOOL is_const, is_volatile, is_struct, is_signed, is_unsigned;
240
const char *iter, *base_type, *catch_unsigned, *proto_str;
241
char dest_type, *type_str;
242
243
assert (sym && sym->symbol);
244
assert (proto && *proto);
245
assert (arg < 0 || (unsigned)arg == sym->argc);
246
247
248
proto_str = str_match (proto, "const", &is_const);
249
proto_str = str_match (proto_str, "volatile", &is_volatile);
250
proto_str = str_match (proto_str, "struct", &is_struct);
251
if (!is_struct)
252
proto_str = str_match (proto_str, "union", &is_struct);
253
254
catch_unsigned = proto_str;
255
256
proto_str = str_match (proto_str, "unsigned", &is_unsigned);
257
proto_str = str_match (proto_str, "signed", &is_signed);
258
259
/* Can have 'unsigned const' or 'const unsigned' etc */
260
if (!is_const)
261
proto_str = str_match (proto_str, "const", &is_const);
262
if (!is_volatile)
263
proto_str = str_match (proto_str, "volatile", &is_volatile);
264
265
base_type = proto_str;
266
iter = str_find_set (proto_str, " ,*)");
267
if (!iter)
268
return NULL;
269
270
if (arg < 0 && (is_signed || is_unsigned))
271
{
272
/* Prevent calling convention from being swallowed by 'un/signed' alone */
273
if (strncmp (base_type, "int", 3) && strncmp (base_type, "long", 4) &&
274
strncmp (base_type, "short", 5) && strncmp (base_type, "char", 4))
275
{
276
iter = proto_str;
277
base_type = catch_unsigned;
278
} else
279
catch_unsigned = NULL;
280
}
281
else
282
catch_unsigned = NULL;
283
284
/* FIXME: skip const/volatile here too */
285
for (proto_str = iter; *proto_str; proto_str++)
286
if (*proto_str != '*' && *proto_str != ' ')
287
break;
288
289
if (!*proto_str)
290
return NULL;
291
292
type_str = str_substring (proto, proto_str);
293
if (iter == base_type || catch_unsigned)
294
{
295
/* 'unsigned' with no type */
296
type_str = strmake( "%s int", type_str );
297
}
298
symbol_clean_string (type_str);
299
300
dest_type = symbol_get_type (type_str);
301
302
if (arg < 0)
303
{
304
sym->return_text = type_str;
305
sym->return_type = dest_type;
306
}
307
else
308
{
309
sym->arg_type [arg] = dest_type;
310
sym->arg_flag [arg] = is_const ? CT_CONST : is_volatile ? CT_VOLATILE : 0;
311
312
if (*proto_str == ',' || *proto_str == ')')
313
sym->arg_name [arg] = strmake( "arg%u", arg );
314
else
315
{
316
iter = str_find_set (proto_str, " ,)");
317
if (!iter)
318
{
319
free (type_str);
320
return NULL;
321
}
322
sym->arg_name [arg] = str_substring (proto_str, iter);
323
proto_str = iter;
324
}
325
sym->arg_text [arg] = type_str;
326
327
}
328
return proto_str;
329
}
330
331