Commit | Line | Data |
---|---|---|
fbbe92c5 SDJ |
1 | /* Functions that provide the mechanism to parse a syscall XML file |
2 | and get its values. | |
3 | ||
4 | Copyright (C) 1986, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, | |
5 | 1998, 1999, 2000, 2001, 2003, 2004, 2005, 2006, 2007, 2008 | |
6 | Free Software Foundation, Inc. | |
7 | ||
8 | This file is part of GDB. | |
9 | ||
10 | This program is free software; you can redistribute it and/or modify | |
11 | it under the terms of the GNU General Public License as published by | |
12 | the Free Software Foundation; either version 3 of the License, or | |
13 | (at your option) any later version. | |
14 | ||
15 | This program is distributed in the hope that it will be useful, | |
16 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
18 | GNU General Public License for more details. | |
19 | ||
20 | You should have received a copy of the GNU General Public License | |
21 | along with this program. If not, see <http://www.gnu.org/licenses/>. */ | |
22 | ||
23 | #include "defs.h" | |
24 | #include "gdbtypes.h" | |
25 | #include "xml-support.h" | |
26 | #include "xml-syscall.h" | |
27 | ||
28 | /* For the struct syscall definition. */ | |
29 | #include "target.h" | |
30 | ||
31 | #include "filenames.h" | |
32 | ||
33 | #include "gdb_assert.h" | |
34 | ||
35 | #ifndef HAVE_LIBEXPAT | |
36 | ||
37 | /* Dummy functions to indicate that there's no support for fetching | |
38 | syscalls information. */ | |
39 | ||
40 | static void | |
41 | syscall_warn_user (void) | |
42 | { | |
43 | static int have_warned = 0; | |
44 | if (!have_warned) | |
45 | { | |
46 | have_warned = 1; | |
47 | warning (_("Can not parse XML syscalls information; XML support was " | |
48 | "disabled at compile time.")); | |
49 | } | |
50 | } | |
51 | ||
52 | void | |
53 | set_xml_syscall_file_name (const char *name) | |
54 | { | |
55 | syscall_warn_user (); | |
56 | } | |
57 | ||
58 | void | |
59 | get_syscall_by_number (int syscall_number, | |
60 | struct syscall *s) | |
61 | { | |
62 | syscall_warn_user (); | |
63 | s->number = syscall_number; | |
64 | s->name = NULL; | |
65 | } | |
66 | ||
67 | void | |
68 | get_syscall_by_name (const char *syscall_name, | |
69 | struct syscall *s) | |
70 | { | |
71 | syscall_warn_user (); | |
72 | s->number = UNKNOWN_SYSCALL; | |
73 | s->name = syscall_name; | |
74 | } | |
75 | ||
76 | const char ** | |
77 | get_syscall_names (void) | |
78 | { | |
79 | syscall_warn_user (); | |
80 | return NULL; | |
81 | } | |
82 | ||
83 | ||
84 | #else /* ! HAVE_LIBEXPAT */ | |
85 | ||
86 | /* Structure which describes a syscall. */ | |
87 | typedef struct syscall_desc | |
88 | { | |
89 | /* The syscall number. */ | |
90 | ||
91 | int number; | |
92 | ||
93 | /* The syscall name. */ | |
94 | ||
95 | char *name; | |
96 | } *syscall_desc_p; | |
97 | DEF_VEC_P(syscall_desc_p); | |
98 | ||
99 | /* Structure that represents syscalls information. */ | |
100 | struct syscalls_info | |
101 | { | |
102 | /* The syscalls. */ | |
103 | ||
104 | VEC(syscall_desc_p) *syscalls; | |
105 | }; | |
106 | ||
107 | /* Callback data for syscall information parsing. */ | |
108 | struct syscall_parsing_data | |
109 | { | |
110 | /* The syscalls_info we are building. */ | |
111 | ||
112 | struct syscalls_info *sysinfo; | |
113 | }; | |
114 | ||
115 | /* Structure used to store information about the available syscalls in | |
116 | the system. */ | |
117 | static const struct syscalls_info *_sysinfo = NULL; | |
118 | ||
119 | /* A flag to tell if we already initialized the structure above. */ | |
120 | static int have_initialized_sysinfo = 0; | |
121 | ||
122 | /* The filename of the syscall's XML. */ | |
123 | static const char *xml_syscall_file = NULL; | |
124 | ||
125 | static struct syscalls_info * | |
126 | allocate_syscalls_info (void) | |
127 | { | |
128 | return XZALLOC (struct syscalls_info); | |
129 | } | |
130 | ||
131 | static void | |
132 | sysinfo_free_syscalls_desc (struct syscall_desc *sd) | |
133 | { | |
134 | xfree (sd->name); | |
135 | } | |
136 | ||
137 | static void | |
138 | free_syscalls_info (void *arg) | |
139 | { | |
140 | struct syscalls_info *sysinfo = arg; | |
141 | struct syscall_desc *sysdesc; | |
142 | int i; | |
143 | ||
144 | for (i = 0; | |
145 | VEC_iterate (syscall_desc_p, sysinfo->syscalls, i, sysdesc); | |
146 | i++) | |
147 | sysinfo_free_syscalls_desc (sysdesc); | |
148 | VEC_free (syscall_desc_p, sysinfo->syscalls); | |
149 | ||
150 | xfree (sysinfo); | |
151 | } | |
152 | ||
153 | struct cleanup * | |
154 | make_cleanup_free_syscalls_info (struct syscalls_info *sysinfo) | |
155 | { | |
156 | return make_cleanup (free_syscalls_info, sysinfo); | |
157 | } | |
158 | ||
159 | static void | |
160 | syscall_create_syscall_desc (struct syscalls_info *sysinfo, | |
161 | const char *name, int number) | |
162 | { | |
163 | struct syscall_desc *sysdesc = XZALLOC (struct syscall_desc); | |
164 | ||
165 | sysdesc->name = xstrdup (name); | |
166 | sysdesc->number = number; | |
167 | ||
168 | VEC_safe_push (syscall_desc_p, sysinfo->syscalls, sysdesc); | |
169 | } | |
170 | ||
171 | /* Handle the start of a <syscalls_info> element. */ | |
172 | static void | |
173 | syscall_start_syscalls_info (struct gdb_xml_parser *parser, | |
174 | const struct gdb_xml_element *element, | |
175 | void *user_data, | |
176 | VEC(gdb_xml_value_s) *attributes) | |
177 | { | |
178 | struct syscall_parsing_data *data = user_data; | |
179 | struct syscalls_info *sysinfo = data->sysinfo; | |
180 | } | |
181 | ||
182 | /* Handle the start of a <syscall> element. */ | |
183 | static void | |
184 | syscall_start_syscall (struct gdb_xml_parser *parser, | |
185 | const struct gdb_xml_element *element, | |
186 | void *user_data, VEC(gdb_xml_value_s) *attributes) | |
187 | { | |
188 | struct syscall_parsing_data *data = user_data; | |
189 | struct gdb_xml_value *attrs = VEC_address (gdb_xml_value_s, attributes); | |
190 | int len, i; | |
191 | /* syscall info. */ | |
192 | char *name = NULL; | |
193 | int number = 0; | |
194 | ||
195 | len = VEC_length (gdb_xml_value_s, attributes); | |
196 | ||
197 | for (i = 0; i < len; i++) | |
198 | { | |
199 | if (strcmp (attrs[i].name, "name") == 0) | |
200 | name = attrs[i].value; | |
201 | else if (strcmp (attrs[i].name, "number") == 0) | |
202 | number = * (ULONGEST *) attrs[i].value; | |
203 | else | |
204 | internal_error (__FILE__, __LINE__, | |
205 | _("Unknown attribute name '%s'."), attrs[i].name); | |
206 | } | |
207 | ||
208 | syscall_create_syscall_desc (data->sysinfo, name, number); | |
209 | } | |
210 | ||
211 | ||
212 | /* The elements and attributes of an XML syscall document. */ | |
213 | static const struct gdb_xml_attribute syscall_attr[] = { | |
214 | { "number", GDB_XML_AF_NONE, gdb_xml_parse_attr_ulongest, NULL }, | |
215 | { "name", GDB_XML_AF_NONE, NULL, NULL }, | |
216 | { NULL, GDB_XML_AF_NONE, NULL, NULL } | |
217 | }; | |
218 | ||
219 | static const struct gdb_xml_element syscalls_info_children[] = { | |
220 | { "syscall", syscall_attr, NULL, | |
221 | GDB_XML_EF_OPTIONAL | GDB_XML_EF_REPEATABLE, | |
222 | syscall_start_syscall, NULL }, | |
223 | { NULL, NULL, NULL, GDB_XML_EF_NONE, NULL, NULL } | |
224 | }; | |
225 | ||
226 | static const struct gdb_xml_element syselements[] = { | |
227 | { "syscalls_info", NULL, syscalls_info_children, | |
228 | GDB_XML_EF_NONE, syscall_start_syscalls_info, NULL }, | |
229 | { NULL, NULL, NULL, GDB_XML_EF_NONE, NULL, NULL } | |
230 | }; | |
231 | ||
232 | static struct syscalls_info * | |
233 | syscall_parse_xml (const char *document, xml_fetch_another fetcher, | |
234 | void *fetcher_baton) | |
235 | { | |
236 | struct cleanup *result_cleanup; | |
237 | struct gdb_xml_parser *parser; | |
238 | struct syscall_parsing_data data; | |
239 | char *expanded_text; | |
240 | int i; | |
241 | ||
242 | parser = gdb_xml_create_parser_and_cleanup (_("syscalls info"), | |
243 | syselements, &data); | |
244 | ||
245 | memset (&data, 0, sizeof (struct syscall_parsing_data)); | |
246 | data.sysinfo = allocate_syscalls_info (); | |
247 | result_cleanup = make_cleanup_free_syscalls_info (data.sysinfo); | |
248 | ||
249 | if (gdb_xml_parse (parser, document) == 0) | |
250 | { | |
251 | /* Parsed successfully. */ | |
252 | discard_cleanups (result_cleanup); | |
253 | return data.sysinfo; | |
254 | } | |
255 | else | |
256 | { | |
257 | warning (_("Could not load XML syscalls info; ignoring")); | |
258 | do_cleanups (result_cleanup); | |
259 | return NULL; | |
260 | } | |
261 | } | |
262 | ||
263 | /* Function responsible for initializing the information | |
264 | about the syscalls. It reads the XML file and fills the | |
265 | struct syscalls_info with the values. | |
266 | ||
267 | Returns the struct syscalls_info if the file is valid, NULL otherwise. */ | |
268 | static const struct syscalls_info * | |
269 | xml_init_syscalls_info (const char *filename) | |
270 | { | |
271 | char *full_file; | |
272 | char *dirname; | |
273 | struct syscalls_info *sysinfo; | |
274 | struct cleanup *back_to; | |
275 | ||
276 | full_file = xml_fetch_content_from_file (filename, gdb_datadir); | |
277 | if (full_file == NULL) | |
278 | { | |
279 | warning (_("Could not open \"%s\""), filename); | |
280 | return NULL; | |
281 | } | |
282 | ||
283 | back_to = make_cleanup (xfree, full_file); | |
284 | ||
285 | dirname = ldirname (filename); | |
286 | if (dirname != NULL) | |
287 | make_cleanup (xfree, dirname); | |
288 | ||
289 | sysinfo = syscall_parse_xml (full_file, xml_fetch_content_from_file, dirname); | |
290 | do_cleanups (back_to); | |
291 | ||
292 | return sysinfo; | |
293 | } | |
294 | ||
295 | /* Initializes the syscalls_info structure according to the | |
296 | architecture. */ | |
297 | static void | |
298 | init_sysinfo (void) | |
299 | { | |
300 | /* Did we already try to initialize the structure? */ | |
301 | if (have_initialized_sysinfo) | |
302 | return; | |
303 | /* if (xml_syscall_file == NULL) | |
304 | internal_error (__FILE__, __LINE__, | |
305 | _("This architecture has not set the XML syscall file " | |
306 | "name. This is a bug and should not happen; please " | |
307 | "report it.")); */ | |
308 | ||
309 | _sysinfo = xml_init_syscalls_info (xml_syscall_file); | |
310 | ||
311 | have_initialized_sysinfo = 1; | |
312 | ||
313 | if (_sysinfo == NULL) | |
314 | { | |
315 | if (xml_syscall_file) | |
316 | /* The initialization failed. Let's show a warning | |
317 | message to the user (just this time) and leave. */ | |
318 | warning (_("Could not load the syscall XML file `%s'.\n\ | |
319 | GDB will not be able to display syscall names."), xml_syscall_file); | |
320 | else | |
321 | /* There's no file to open. Let's warn the user. */ | |
322 | warning (_("There is no XML file to open.\n\ | |
323 | GDB will not be able to display syscall names.")); | |
324 | } | |
325 | } | |
326 | ||
327 | static int | |
328 | xml_get_syscall_number (const struct syscalls_info *sysinfo, | |
329 | const char *syscall_name) | |
330 | { | |
331 | struct syscall_desc *sysdesc; | |
332 | int i; | |
333 | ||
334 | if (sysinfo == NULL | |
335 | || syscall_name == NULL) | |
336 | return UNKNOWN_SYSCALL; | |
337 | ||
338 | for (i = 0; | |
339 | VEC_iterate(syscall_desc_p, sysinfo->syscalls, i, sysdesc); | |
340 | i++) | |
341 | if (strcmp (sysdesc->name, syscall_name) == 0) | |
342 | return sysdesc->number; | |
343 | ||
344 | return UNKNOWN_SYSCALL; | |
345 | } | |
346 | ||
347 | static const char * | |
348 | xml_get_syscall_name (const struct syscalls_info *sysinfo, | |
349 | int syscall_number) | |
350 | { | |
351 | struct syscall_desc *sysdesc; | |
352 | int i; | |
353 | ||
354 | if (sysinfo == NULL | |
355 | || syscall_number < 0) | |
356 | return NULL; | |
357 | ||
358 | for (i = 0; | |
359 | VEC_iterate(syscall_desc_p, sysinfo->syscalls, i, sysdesc); | |
360 | i++) | |
361 | if (sysdesc->number == syscall_number) | |
362 | return sysdesc->name; | |
363 | ||
364 | return NULL; | |
365 | } | |
366 | ||
367 | static int | |
368 | xml_number_of_syscalls (const struct syscalls_info *sysinfo) | |
369 | { | |
370 | return (sysinfo == NULL ? 0 : VEC_length (syscall_desc_p, | |
371 | sysinfo->syscalls)); | |
372 | } | |
373 | ||
374 | static const char ** | |
375 | xml_list_of_syscalls (const struct syscalls_info *sysinfo) | |
376 | { | |
377 | struct syscall_desc *sysdesc; | |
378 | const char **names = NULL; | |
379 | int nsyscalls; | |
380 | int i; | |
381 | ||
382 | if (sysinfo == NULL) | |
383 | return NULL; | |
384 | ||
385 | nsyscalls = VEC_length (syscall_desc_p, sysinfo->syscalls); | |
386 | names = xmalloc ((nsyscalls + 1) * sizeof (char *)); | |
387 | ||
388 | for (i = 0; | |
389 | VEC_iterate (syscall_desc_p, sysinfo->syscalls, i, sysdesc); | |
390 | i++) | |
391 | names[i] = sysdesc->name; | |
392 | ||
393 | names[i] = NULL; | |
394 | ||
395 | return names; | |
396 | } | |
397 | ||
398 | void | |
399 | set_xml_syscall_file_name (const char *name) | |
400 | { | |
401 | xml_syscall_file = name; | |
402 | } | |
403 | ||
404 | void | |
405 | get_syscall_by_number (int syscall_number, | |
406 | struct syscall *s) | |
407 | { | |
408 | init_sysinfo (); | |
409 | ||
410 | s->number = syscall_number; | |
411 | s->name = xml_get_syscall_name (_sysinfo, syscall_number); | |
412 | } | |
413 | ||
414 | void | |
415 | get_syscall_by_name (const char *syscall_name, | |
416 | struct syscall *s) | |
417 | { | |
418 | init_sysinfo (); | |
419 | ||
420 | s->number = xml_get_syscall_number (_sysinfo, syscall_name); | |
421 | s->name = syscall_name; | |
422 | } | |
423 | ||
424 | const char ** | |
425 | get_syscall_names (void) | |
426 | { | |
427 | init_sysinfo (); | |
428 | ||
429 | return xml_list_of_syscalls (_sysinfo); | |
430 | } | |
431 | ||
432 | #endif /* ! HAVE_LIBEXPAT */ |