GDB (API)
|
00001 /* XML target description support for GDB. 00002 00003 Copyright (C) 2006-2013 Free Software Foundation, Inc. 00004 00005 Contributed by CodeSourcery. 00006 00007 This file is part of GDB. 00008 00009 This program is free software; you can redistribute it and/or modify 00010 it under the terms of the GNU General Public License as published by 00011 the Free Software Foundation; either version 3 of the License, or 00012 (at your option) any later version. 00013 00014 This program is distributed in the hope that it will be useful, 00015 but WITHOUT ANY WARRANTY; without even the implied warranty of 00016 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00017 GNU General Public License for more details. 00018 00019 You should have received a copy of the GNU General Public License 00020 along with this program. If not, see <http://www.gnu.org/licenses/>. */ 00021 00022 #include "defs.h" 00023 #include "target.h" 00024 #include "target-descriptions.h" 00025 #include "xml-support.h" 00026 #include "xml-tdesc.h" 00027 #include "osabi.h" 00028 00029 #include "filenames.h" 00030 00031 #include "gdb_assert.h" 00032 00033 #if !defined(HAVE_LIBEXPAT) 00034 00035 /* Parse DOCUMENT into a target description. Or don't, since we don't have 00036 an XML parser. */ 00037 00038 static struct target_desc * 00039 tdesc_parse_xml (const char *document, xml_fetch_another fetcher, 00040 void *fetcher_baton) 00041 { 00042 static int have_warned; 00043 00044 if (!have_warned) 00045 { 00046 have_warned = 1; 00047 warning (_("Can not parse XML target description; XML support was " 00048 "disabled at compile time")); 00049 } 00050 00051 return NULL; 00052 } 00053 00054 #else /* HAVE_LIBEXPAT */ 00055 00056 /* A record of every XML description we have parsed. We never discard 00057 old descriptions, because we never discard gdbarches. As long as we 00058 have a gdbarch referencing this description, we want to have a copy 00059 of it here, so that if we parse the same XML document again we can 00060 return the same "struct target_desc *"; if they are not singletons, 00061 then we will create unnecessary duplicate gdbarches. See 00062 gdbarch_list_lookup_by_info. */ 00063 00064 struct tdesc_xml_cache 00065 { 00066 const char *xml_document; 00067 struct target_desc *tdesc; 00068 }; 00069 typedef struct tdesc_xml_cache tdesc_xml_cache_s; 00070 DEF_VEC_O(tdesc_xml_cache_s); 00071 00072 static VEC(tdesc_xml_cache_s) *xml_cache; 00073 00074 /* Callback data for target description parsing. */ 00075 00076 struct tdesc_parsing_data 00077 { 00078 /* The target description we are building. */ 00079 struct target_desc *tdesc; 00080 00081 /* The target feature we are currently parsing, or last parsed. */ 00082 struct tdesc_feature *current_feature; 00083 00084 /* The register number to use for the next register we see, if 00085 it does not have its own. This starts at zero. */ 00086 int next_regnum; 00087 00088 /* The struct or union we are currently parsing, or last parsed. */ 00089 struct tdesc_type *current_type; 00090 00091 /* The byte size of the current struct type, if specified. Zero 00092 if not specified. */ 00093 int current_type_size; 00094 00095 /* Whether the current type is a flags type. */ 00096 int current_type_is_flags; 00097 }; 00098 00099 /* Handle the end of an <architecture> element and its value. */ 00100 00101 static void 00102 tdesc_end_arch (struct gdb_xml_parser *parser, 00103 const struct gdb_xml_element *element, 00104 void *user_data, const char *body_text) 00105 { 00106 struct tdesc_parsing_data *data = user_data; 00107 const struct bfd_arch_info *arch; 00108 00109 arch = bfd_scan_arch (body_text); 00110 if (arch == NULL) 00111 gdb_xml_error (parser, _("Target description specified unknown " 00112 "architecture \"%s\""), body_text); 00113 set_tdesc_architecture (data->tdesc, arch); 00114 } 00115 00116 /* Handle the end of an <osabi> element and its value. */ 00117 00118 static void 00119 tdesc_end_osabi (struct gdb_xml_parser *parser, 00120 const struct gdb_xml_element *element, 00121 void *user_data, const char *body_text) 00122 { 00123 struct tdesc_parsing_data *data = user_data; 00124 enum gdb_osabi osabi; 00125 00126 osabi = osabi_from_tdesc_string (body_text); 00127 if (osabi == GDB_OSABI_UNKNOWN) 00128 warning (_("Target description specified unknown osabi \"%s\""), 00129 body_text); 00130 else 00131 set_tdesc_osabi (data->tdesc, osabi); 00132 } 00133 00134 /* Handle the end of a <compatible> element and its value. */ 00135 00136 static void 00137 tdesc_end_compatible (struct gdb_xml_parser *parser, 00138 const struct gdb_xml_element *element, 00139 void *user_data, const char *body_text) 00140 { 00141 struct tdesc_parsing_data *data = user_data; 00142 const struct bfd_arch_info *arch; 00143 00144 arch = bfd_scan_arch (body_text); 00145 tdesc_add_compatible (data->tdesc, arch); 00146 } 00147 00148 /* Handle the start of a <target> element. */ 00149 00150 static void 00151 tdesc_start_target (struct gdb_xml_parser *parser, 00152 const struct gdb_xml_element *element, 00153 void *user_data, VEC(gdb_xml_value_s) *attributes) 00154 { 00155 char *version = xml_find_attribute (attributes, "version")->value; 00156 00157 if (strcmp (version, "1.0") != 0) 00158 gdb_xml_error (parser, 00159 _("Target description has unsupported version \"%s\""), 00160 version); 00161 } 00162 00163 /* Handle the start of a <feature> element. */ 00164 00165 static void 00166 tdesc_start_feature (struct gdb_xml_parser *parser, 00167 const struct gdb_xml_element *element, 00168 void *user_data, VEC(gdb_xml_value_s) *attributes) 00169 { 00170 struct tdesc_parsing_data *data = user_data; 00171 char *name = xml_find_attribute (attributes, "name")->value; 00172 00173 data->current_feature = tdesc_create_feature (data->tdesc, name); 00174 } 00175 00176 /* Handle the start of a <reg> element. Fill in the optional 00177 attributes and attach it to the containing feature. */ 00178 00179 static void 00180 tdesc_start_reg (struct gdb_xml_parser *parser, 00181 const struct gdb_xml_element *element, 00182 void *user_data, VEC(gdb_xml_value_s) *attributes) 00183 { 00184 struct tdesc_parsing_data *data = user_data; 00185 struct gdb_xml_value *attrs = VEC_address (gdb_xml_value_s, attributes); 00186 int ix = 0, length; 00187 char *name, *group, *type; 00188 int bitsize, regnum, save_restore; 00189 00190 length = VEC_length (gdb_xml_value_s, attributes); 00191 00192 name = attrs[ix++].value; 00193 bitsize = * (ULONGEST *) attrs[ix++].value; 00194 00195 if (ix < length && strcmp (attrs[ix].name, "regnum") == 0) 00196 regnum = * (ULONGEST *) attrs[ix++].value; 00197 else 00198 regnum = data->next_regnum; 00199 00200 if (ix < length && strcmp (attrs[ix].name, "type") == 0) 00201 type = attrs[ix++].value; 00202 else 00203 type = "int"; 00204 00205 if (ix < length && strcmp (attrs[ix].name, "group") == 0) 00206 group = attrs[ix++].value; 00207 else 00208 group = NULL; 00209 00210 if (ix < length && strcmp (attrs[ix].name, "save-restore") == 0) 00211 save_restore = * (ULONGEST *) attrs[ix++].value; 00212 else 00213 save_restore = 1; 00214 00215 if (strcmp (type, "int") != 0 00216 && strcmp (type, "float") != 0 00217 && tdesc_named_type (data->current_feature, type) == NULL) 00218 gdb_xml_error (parser, _("Register \"%s\" has unknown type \"%s\""), 00219 name, type); 00220 00221 tdesc_create_reg (data->current_feature, name, regnum, save_restore, group, 00222 bitsize, type); 00223 00224 data->next_regnum = regnum + 1; 00225 } 00226 00227 /* Handle the start of a <union> element. Initialize the type and 00228 record it with the current feature. */ 00229 00230 static void 00231 tdesc_start_union (struct gdb_xml_parser *parser, 00232 const struct gdb_xml_element *element, 00233 void *user_data, VEC(gdb_xml_value_s) *attributes) 00234 { 00235 struct tdesc_parsing_data *data = user_data; 00236 char *id = xml_find_attribute (attributes, "id")->value; 00237 00238 data->current_type = tdesc_create_union (data->current_feature, id); 00239 data->current_type_size = 0; 00240 data->current_type_is_flags = 0; 00241 } 00242 00243 /* Handle the start of a <struct> element. Initialize the type and 00244 record it with the current feature. */ 00245 00246 static void 00247 tdesc_start_struct (struct gdb_xml_parser *parser, 00248 const struct gdb_xml_element *element, 00249 void *user_data, VEC(gdb_xml_value_s) *attributes) 00250 { 00251 struct tdesc_parsing_data *data = user_data; 00252 char *id = xml_find_attribute (attributes, "id")->value; 00253 struct tdesc_type *type; 00254 struct gdb_xml_value *attr; 00255 00256 type = tdesc_create_struct (data->current_feature, id); 00257 data->current_type = type; 00258 data->current_type_size = 0; 00259 data->current_type_is_flags = 0; 00260 00261 attr = xml_find_attribute (attributes, "size"); 00262 if (attr != NULL) 00263 { 00264 int size = (int) * (ULONGEST *) attr->value; 00265 00266 tdesc_set_struct_size (type, size); 00267 data->current_type_size = size; 00268 } 00269 } 00270 00271 static void 00272 tdesc_start_flags (struct gdb_xml_parser *parser, 00273 const struct gdb_xml_element *element, 00274 void *user_data, VEC(gdb_xml_value_s) *attributes) 00275 { 00276 struct tdesc_parsing_data *data = user_data; 00277 char *id = xml_find_attribute (attributes, "id")->value; 00278 int length = (int) * (ULONGEST *) 00279 xml_find_attribute (attributes, "size")->value; 00280 struct tdesc_type *type; 00281 00282 type = tdesc_create_flags (data->current_feature, id, length); 00283 00284 data->current_type = type; 00285 data->current_type_size = 0; 00286 data->current_type_is_flags = 1; 00287 } 00288 00289 /* Handle the start of a <field> element. Attach the field to the 00290 current struct or union. */ 00291 00292 static void 00293 tdesc_start_field (struct gdb_xml_parser *parser, 00294 const struct gdb_xml_element *element, 00295 void *user_data, VEC(gdb_xml_value_s) *attributes) 00296 { 00297 struct tdesc_parsing_data *data = user_data; 00298 struct gdb_xml_value *attr; 00299 struct tdesc_type *field_type; 00300 char *field_name, *field_type_id; 00301 int start, end; 00302 00303 field_name = xml_find_attribute (attributes, "name")->value; 00304 00305 attr = xml_find_attribute (attributes, "type"); 00306 if (attr != NULL) 00307 field_type_id = attr->value; 00308 else 00309 field_type_id = NULL; 00310 00311 attr = xml_find_attribute (attributes, "start"); 00312 if (attr != NULL) 00313 start = * (ULONGEST *) attr->value; 00314 else 00315 start = -1; 00316 00317 attr = xml_find_attribute (attributes, "end"); 00318 if (attr != NULL) 00319 end = * (ULONGEST *) attr->value; 00320 else 00321 end = -1; 00322 00323 if (field_type_id != NULL) 00324 { 00325 if (data->current_type_is_flags) 00326 gdb_xml_error (parser, _("Cannot add typed field \"%s\" to flags"), 00327 field_name); 00328 if (data->current_type_size != 0) 00329 gdb_xml_error (parser, 00330 _("Explicitly sized type can not " 00331 "contain non-bitfield \"%s\""), 00332 field_name); 00333 00334 field_type = tdesc_named_type (data->current_feature, field_type_id); 00335 if (field_type == NULL) 00336 gdb_xml_error (parser, _("Field \"%s\" references undefined " 00337 "type \"%s\""), 00338 field_name, field_type_id); 00339 00340 tdesc_add_field (data->current_type, field_name, field_type); 00341 } 00342 else if (start != -1 && end != -1) 00343 { 00344 struct tdesc_type *t = data->current_type; 00345 00346 if (data->current_type_is_flags) 00347 tdesc_add_flag (t, start, field_name); 00348 else 00349 { 00350 if (data->current_type_size == 0) 00351 gdb_xml_error (parser, 00352 _("Implicitly sized type can " 00353 "not contain bitfield \"%s\""), 00354 field_name); 00355 00356 if (end >= 64) 00357 gdb_xml_error (parser, 00358 _("Bitfield \"%s\" goes past " 00359 "64 bits (unsupported)"), 00360 field_name); 00361 00362 /* Assume that the bit numbering in XML is "lsb-zero". Most 00363 architectures other than PowerPC use this ordering. In 00364 the future, we can add an XML tag to indicate "msb-zero" 00365 numbering. */ 00366 if (start > end) 00367 gdb_xml_error (parser, _("Bitfield \"%s\" has start after end"), 00368 field_name); 00369 00370 if (end >= data->current_type_size * TARGET_CHAR_BIT) 00371 gdb_xml_error (parser, 00372 _("Bitfield \"%s\" does not fit in struct")); 00373 00374 tdesc_add_bitfield (t, field_name, start, end); 00375 } 00376 } 00377 else 00378 gdb_xml_error (parser, _("Field \"%s\" has neither type nor bit position"), 00379 field_name); 00380 } 00381 00382 /* Handle the start of a <vector> element. Initialize the type and 00383 record it with the current feature. */ 00384 00385 static void 00386 tdesc_start_vector (struct gdb_xml_parser *parser, 00387 const struct gdb_xml_element *element, 00388 void *user_data, VEC(gdb_xml_value_s) *attributes) 00389 { 00390 struct tdesc_parsing_data *data = user_data; 00391 struct gdb_xml_value *attrs = VEC_address (gdb_xml_value_s, attributes); 00392 struct tdesc_type *field_type; 00393 char *id, *field_type_id; 00394 int count; 00395 00396 id = attrs[0].value; 00397 field_type_id = attrs[1].value; 00398 count = * (ULONGEST *) attrs[2].value; 00399 00400 field_type = tdesc_named_type (data->current_feature, field_type_id); 00401 if (field_type == NULL) 00402 gdb_xml_error (parser, _("Vector \"%s\" references undefined type \"%s\""), 00403 id, field_type_id); 00404 00405 tdesc_create_vector (data->current_feature, id, field_type, count); 00406 } 00407 00408 /* The elements and attributes of an XML target description. */ 00409 00410 static const struct gdb_xml_attribute field_attributes[] = { 00411 { "name", GDB_XML_AF_NONE, NULL, NULL }, 00412 { "type", GDB_XML_AF_OPTIONAL, NULL, NULL }, 00413 { "start", GDB_XML_AF_OPTIONAL, gdb_xml_parse_attr_ulongest, NULL }, 00414 { "end", GDB_XML_AF_OPTIONAL, gdb_xml_parse_attr_ulongest, NULL }, 00415 { NULL, GDB_XML_AF_NONE, NULL, NULL } 00416 }; 00417 00418 static const struct gdb_xml_element struct_union_children[] = { 00419 { "field", field_attributes, NULL, GDB_XML_EF_REPEATABLE, 00420 tdesc_start_field, NULL }, 00421 { NULL, NULL, NULL, GDB_XML_EF_NONE, NULL, NULL } 00422 }; 00423 00424 static const struct gdb_xml_attribute reg_attributes[] = { 00425 { "name", GDB_XML_AF_NONE, NULL, NULL }, 00426 { "bitsize", GDB_XML_AF_NONE, gdb_xml_parse_attr_ulongest, NULL }, 00427 { "regnum", GDB_XML_AF_OPTIONAL, gdb_xml_parse_attr_ulongest, NULL }, 00428 { "type", GDB_XML_AF_OPTIONAL, NULL, NULL }, 00429 { "group", GDB_XML_AF_OPTIONAL, NULL, NULL }, 00430 { "save-restore", GDB_XML_AF_OPTIONAL, 00431 gdb_xml_parse_attr_enum, gdb_xml_enums_boolean }, 00432 { NULL, GDB_XML_AF_NONE, NULL, NULL } 00433 }; 00434 00435 static const struct gdb_xml_attribute struct_union_attributes[] = { 00436 { "id", GDB_XML_AF_NONE, NULL, NULL }, 00437 { "size", GDB_XML_AF_OPTIONAL, gdb_xml_parse_attr_ulongest, NULL}, 00438 { NULL, GDB_XML_AF_NONE, NULL, NULL } 00439 }; 00440 00441 static const struct gdb_xml_attribute flags_attributes[] = { 00442 { "id", GDB_XML_AF_NONE, NULL, NULL }, 00443 { "size", GDB_XML_AF_NONE, gdb_xml_parse_attr_ulongest, NULL}, 00444 { NULL, GDB_XML_AF_NONE, NULL, NULL } 00445 }; 00446 00447 static const struct gdb_xml_attribute vector_attributes[] = { 00448 { "id", GDB_XML_AF_NONE, NULL, NULL }, 00449 { "type", GDB_XML_AF_NONE, NULL, NULL }, 00450 { "count", GDB_XML_AF_NONE, gdb_xml_parse_attr_ulongest, NULL }, 00451 { NULL, GDB_XML_AF_NONE, NULL, NULL } 00452 }; 00453 00454 static const struct gdb_xml_attribute feature_attributes[] = { 00455 { "name", GDB_XML_AF_NONE, NULL, NULL }, 00456 { NULL, GDB_XML_AF_NONE, NULL, NULL } 00457 }; 00458 00459 static const struct gdb_xml_element feature_children[] = { 00460 { "reg", reg_attributes, NULL, 00461 GDB_XML_EF_OPTIONAL | GDB_XML_EF_REPEATABLE, 00462 tdesc_start_reg, NULL }, 00463 { "struct", struct_union_attributes, struct_union_children, 00464 GDB_XML_EF_OPTIONAL | GDB_XML_EF_REPEATABLE, 00465 tdesc_start_struct, NULL }, 00466 { "union", struct_union_attributes, struct_union_children, 00467 GDB_XML_EF_OPTIONAL | GDB_XML_EF_REPEATABLE, 00468 tdesc_start_union, NULL }, 00469 { "flags", flags_attributes, struct_union_children, 00470 GDB_XML_EF_OPTIONAL | GDB_XML_EF_REPEATABLE, 00471 tdesc_start_flags, NULL }, 00472 { "vector", vector_attributes, NULL, 00473 GDB_XML_EF_OPTIONAL | GDB_XML_EF_REPEATABLE, 00474 tdesc_start_vector, NULL }, 00475 { NULL, NULL, NULL, GDB_XML_EF_NONE, NULL, NULL } 00476 }; 00477 00478 static const struct gdb_xml_attribute target_attributes[] = { 00479 { "version", GDB_XML_AF_NONE, NULL, NULL }, 00480 { NULL, GDB_XML_AF_NONE, NULL, NULL } 00481 }; 00482 00483 static const struct gdb_xml_element target_children[] = { 00484 { "architecture", NULL, NULL, GDB_XML_EF_OPTIONAL, 00485 NULL, tdesc_end_arch }, 00486 { "osabi", NULL, NULL, GDB_XML_EF_OPTIONAL, 00487 NULL, tdesc_end_osabi }, 00488 { "compatible", NULL, NULL, GDB_XML_EF_OPTIONAL | GDB_XML_EF_REPEATABLE, 00489 NULL, tdesc_end_compatible }, 00490 { "feature", feature_attributes, feature_children, 00491 GDB_XML_EF_OPTIONAL | GDB_XML_EF_REPEATABLE, 00492 tdesc_start_feature, NULL }, 00493 { NULL, NULL, NULL, GDB_XML_EF_NONE, NULL, NULL } 00494 }; 00495 00496 static const struct gdb_xml_element tdesc_elements[] = { 00497 { "target", target_attributes, target_children, GDB_XML_EF_NONE, 00498 tdesc_start_target, NULL }, 00499 { NULL, NULL, NULL, GDB_XML_EF_NONE, NULL, NULL } 00500 }; 00501 00502 /* Parse DOCUMENT into a target description and return it. */ 00503 00504 static struct target_desc * 00505 tdesc_parse_xml (const char *document, xml_fetch_another fetcher, 00506 void *fetcher_baton) 00507 { 00508 struct cleanup *back_to, *result_cleanup; 00509 struct tdesc_parsing_data data; 00510 struct tdesc_xml_cache *cache; 00511 char *expanded_text; 00512 int ix; 00513 00514 /* Expand all XInclude directives. */ 00515 expanded_text = xml_process_xincludes (_("target description"), 00516 document, fetcher, fetcher_baton, 0); 00517 if (expanded_text == NULL) 00518 { 00519 warning (_("Could not load XML target description; ignoring")); 00520 return NULL; 00521 } 00522 00523 /* Check for an exact match in the list of descriptions we have 00524 previously parsed. strcmp is a slightly inefficient way to 00525 do this; an SHA-1 checksum would work as well. */ 00526 for (ix = 0; VEC_iterate (tdesc_xml_cache_s, xml_cache, ix, cache); ix++) 00527 if (strcmp (cache->xml_document, expanded_text) == 0) 00528 { 00529 xfree (expanded_text); 00530 return cache->tdesc; 00531 } 00532 00533 back_to = make_cleanup (null_cleanup, NULL); 00534 00535 memset (&data, 0, sizeof (struct tdesc_parsing_data)); 00536 data.tdesc = allocate_target_description (); 00537 result_cleanup = make_cleanup_free_target_description (data.tdesc); 00538 make_cleanup (xfree, expanded_text); 00539 00540 if (gdb_xml_parse_quick (_("target description"), "gdb-target.dtd", 00541 tdesc_elements, expanded_text, &data) == 0) 00542 { 00543 /* Parsed successfully. */ 00544 struct tdesc_xml_cache new_cache; 00545 00546 new_cache.xml_document = expanded_text; 00547 new_cache.tdesc = data.tdesc; 00548 VEC_safe_push (tdesc_xml_cache_s, xml_cache, &new_cache); 00549 discard_cleanups (result_cleanup); 00550 do_cleanups (back_to); 00551 return data.tdesc; 00552 } 00553 else 00554 { 00555 warning (_("Could not load XML target description; ignoring")); 00556 do_cleanups (back_to); 00557 return NULL; 00558 } 00559 } 00560 #endif /* HAVE_LIBEXPAT */ 00561 00562 00563 /* Read an XML target description from FILENAME. Parse it, and return 00564 the parsed description. */ 00565 00566 const struct target_desc * 00567 file_read_description_xml (const char *filename) 00568 { 00569 struct target_desc *tdesc; 00570 char *tdesc_str; 00571 struct cleanup *back_to; 00572 char *dirname; 00573 00574 tdesc_str = xml_fetch_content_from_file (filename, NULL); 00575 if (tdesc_str == NULL) 00576 { 00577 warning (_("Could not open \"%s\""), filename); 00578 return NULL; 00579 } 00580 00581 back_to = make_cleanup (xfree, tdesc_str); 00582 00583 dirname = ldirname (filename); 00584 if (dirname != NULL) 00585 make_cleanup (xfree, dirname); 00586 00587 tdesc = tdesc_parse_xml (tdesc_str, xml_fetch_content_from_file, dirname); 00588 do_cleanups (back_to); 00589 00590 return tdesc; 00591 } 00592 00593 /* Read a string representation of available features from the target, 00594 using TARGET_OBJECT_AVAILABLE_FEATURES. The returned string is 00595 malloc allocated and NUL-terminated. NAME should be a non-NULL 00596 string identifying the XML document we want; the top level document 00597 is "target.xml". Other calls may be performed for the DTD or 00598 for <xi:include>. */ 00599 00600 static char * 00601 fetch_available_features_from_target (const char *name, void *baton_) 00602 { 00603 struct target_ops *ops = baton_; 00604 00605 /* Read this object as a string. This ensures that a NUL 00606 terminator is added. */ 00607 return target_read_stralloc (ops, 00608 TARGET_OBJECT_AVAILABLE_FEATURES, 00609 name); 00610 } 00611 00612 00613 /* Read an XML target description using OPS. Parse it, and return the 00614 parsed description. */ 00615 00616 const struct target_desc * 00617 target_read_description_xml (struct target_ops *ops) 00618 { 00619 struct target_desc *tdesc; 00620 char *tdesc_str; 00621 struct cleanup *back_to; 00622 00623 tdesc_str = fetch_available_features_from_target ("target.xml", ops); 00624 if (tdesc_str == NULL) 00625 return NULL; 00626 00627 back_to = make_cleanup (xfree, tdesc_str); 00628 tdesc = tdesc_parse_xml (tdesc_str, 00629 fetch_available_features_from_target, 00630 ops); 00631 do_cleanups (back_to); 00632 00633 return tdesc; 00634 }