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