Commit | Line | Data |
---|---|---|
23181151 DJ |
1 | /* XML target description support for GDB. |
2 | ||
3 | Copyright (C) 2006 | |
4 | Free Software Foundation, Inc. | |
5 | ||
6 | Contributed by CodeSourcery. | |
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 2 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, write to the Free Software | |
22 | Foundation, Inc., 51 Franklin Street, Fifth Floor, | |
23 | Boston, MA 02110-1301, USA. */ | |
24 | ||
25 | #include "defs.h" | |
26 | #include "target.h" | |
27 | #include "target-descriptions.h" | |
28 | #include "xml-support.h" | |
29 | #include "xml-tdesc.h" | |
30 | ||
108546a0 DJ |
31 | #include "filenames.h" |
32 | ||
23181151 DJ |
33 | #include "gdb_assert.h" |
34 | ||
35 | #if !defined(HAVE_LIBEXPAT) | |
36 | ||
37 | /* Parse DOCUMENT into a target description. Or don't, since we don't have | |
38 | an XML parser. */ | |
39 | ||
40 | static struct target_desc * | |
108546a0 DJ |
41 | tdesc_parse_xml (const char *document, xml_fetch_another fetcher, |
42 | void *fetcher_baton) | |
23181151 DJ |
43 | { |
44 | static int have_warned; | |
45 | ||
46 | if (!have_warned) | |
47 | { | |
48 | have_warned = 1; | |
49 | warning (_("Can not parse XML target description; XML support was " | |
50 | "disabled at compile time")); | |
51 | } | |
52 | ||
53 | return NULL; | |
54 | } | |
55 | ||
56 | #else /* HAVE_LIBEXPAT */ | |
57 | ||
58 | /* Callback data for target description parsing. */ | |
59 | ||
60 | struct tdesc_parsing_data | |
61 | { | |
62 | /* The target description we are building. */ | |
63 | struct target_desc *tdesc; | |
64 | }; | |
65 | ||
66 | /* Handle the end of an <architecture> element and its value. */ | |
67 | ||
68 | static void | |
69 | tdesc_end_arch (struct gdb_xml_parser *parser, | |
70 | const struct gdb_xml_element *element, | |
71 | void *user_data, const char *body_text) | |
72 | { | |
73 | struct tdesc_parsing_data *data = user_data; | |
74 | const struct bfd_arch_info *arch; | |
75 | ||
76 | arch = bfd_scan_arch (body_text); | |
77 | if (arch == NULL) | |
78 | gdb_xml_error (parser, _("Target description specified unknown " | |
79 | "architecture \"%s\""), body_text); | |
80 | set_tdesc_architecture (data->tdesc, arch); | |
81 | } | |
82 | ||
83 | /* The elements and attributes of an XML target description. */ | |
84 | ||
85 | const struct gdb_xml_element target_children[] = { | |
86 | { "architecture", NULL, NULL, GDB_XML_EF_OPTIONAL, | |
87 | NULL, tdesc_end_arch }, | |
88 | { NULL, NULL, NULL, GDB_XML_EF_NONE, NULL, NULL } | |
89 | }; | |
90 | ||
91 | const struct gdb_xml_element tdesc_elements[] = { | |
92 | { "target", NULL, target_children, GDB_XML_EF_NONE, | |
93 | NULL, NULL }, | |
94 | { NULL, NULL, NULL, GDB_XML_EF_NONE, NULL, NULL } | |
95 | }; | |
96 | ||
97 | /* Parse DOCUMENT into a target description and return it. */ | |
98 | ||
99 | static struct target_desc * | |
108546a0 DJ |
100 | tdesc_parse_xml (const char *document, xml_fetch_another fetcher, |
101 | void *fetcher_baton) | |
23181151 DJ |
102 | { |
103 | struct cleanup *back_to, *result_cleanup; | |
104 | struct gdb_xml_parser *parser; | |
105 | struct tdesc_parsing_data data; | |
108546a0 | 106 | char *expanded_text; |
23181151 | 107 | |
108546a0 DJ |
108 | /* Expand all XInclude directives. */ |
109 | expanded_text = xml_process_xincludes (_("target description"), | |
110 | document, fetcher, fetcher_baton, 0); | |
111 | if (expanded_text == NULL) | |
112 | { | |
113 | warning (_("Could not load XML target description; ignoring")); | |
114 | return NULL; | |
115 | } | |
116 | back_to = make_cleanup (xfree, expanded_text); | |
23181151 | 117 | |
23181151 DJ |
118 | parser = gdb_xml_create_parser_and_cleanup (_("target description"), |
119 | tdesc_elements, &data); | |
108546a0 | 120 | gdb_xml_use_dtd (parser, "gdb-target.dtd"); |
23181151 | 121 | |
108546a0 | 122 | memset (&data, 0, sizeof (struct tdesc_parsing_data)); |
23181151 DJ |
123 | data.tdesc = allocate_target_description (); |
124 | result_cleanup = make_cleanup_free_target_description (data.tdesc); | |
125 | ||
108546a0 | 126 | if (gdb_xml_parse (parser, expanded_text) == 0) |
23181151 DJ |
127 | { |
128 | /* Parsed successfully. */ | |
129 | discard_cleanups (result_cleanup); | |
130 | do_cleanups (back_to); | |
131 | return data.tdesc; | |
132 | } | |
133 | else | |
134 | { | |
135 | warning (_("Could not load XML target description; ignoring")); | |
136 | do_cleanups (back_to); | |
137 | return NULL; | |
138 | } | |
139 | } | |
23181151 DJ |
140 | #endif /* HAVE_LIBEXPAT */ |
141 | \f | |
142 | ||
143 | /* Close FILE. */ | |
144 | ||
145 | static void | |
146 | do_cleanup_fclose (void *file) | |
147 | { | |
148 | fclose (file); | |
149 | } | |
150 | ||
151 | /* Open FILENAME, read all its text into memory, close it, and return | |
152 | the text. If something goes wrong, return NULL and warn. */ | |
153 | ||
154 | static char * | |
108546a0 | 155 | fetch_xml_from_file (const char *filename, void *baton) |
23181151 | 156 | { |
108546a0 | 157 | const char *dirname = baton; |
23181151 DJ |
158 | FILE *file; |
159 | struct cleanup *back_to; | |
160 | char *text; | |
161 | size_t len, offset; | |
162 | ||
108546a0 | 163 | if (dirname && *dirname) |
23181151 | 164 | { |
108546a0 DJ |
165 | char *fullname = concat (dirname, "/", filename, NULL); |
166 | if (fullname == NULL) | |
167 | nomem (0); | |
168 | file = fopen (fullname, FOPEN_RT); | |
169 | xfree (fullname); | |
23181151 | 170 | } |
108546a0 DJ |
171 | else |
172 | file = fopen (filename, FOPEN_RT); | |
173 | ||
174 | if (file == NULL) | |
175 | return NULL; | |
176 | ||
23181151 DJ |
177 | back_to = make_cleanup (do_cleanup_fclose, file); |
178 | ||
179 | /* Read in the whole file, one chunk at a time. */ | |
180 | len = 4096; | |
181 | offset = 0; | |
182 | text = xmalloc (len); | |
183 | make_cleanup (free_current_contents, &text); | |
184 | while (1) | |
185 | { | |
186 | size_t bytes_read; | |
187 | ||
188 | /* Continue reading where the last read left off. Leave at least | |
189 | one byte so that we can NUL-terminate the result. */ | |
190 | bytes_read = fread (text + offset, 1, len - offset - 1, file); | |
191 | if (ferror (file)) | |
192 | { | |
193 | warning (_("Read error from \"%s\""), filename); | |
194 | do_cleanups (back_to); | |
195 | return NULL; | |
196 | } | |
197 | ||
198 | offset += bytes_read; | |
199 | ||
200 | if (feof (file)) | |
201 | break; | |
202 | ||
203 | len = len * 2; | |
204 | text = xrealloc (text, len); | |
205 | } | |
206 | ||
207 | fclose (file); | |
208 | discard_cleanups (back_to); | |
209 | ||
210 | text[offset] = '\0'; | |
211 | return text; | |
212 | } | |
213 | ||
214 | /* Read an XML target description from FILENAME. Parse it, and return | |
215 | the parsed description. */ | |
216 | ||
217 | const struct target_desc * | |
218 | file_read_description_xml (const char *filename) | |
219 | { | |
220 | struct target_desc *tdesc; | |
221 | char *tdesc_str; | |
222 | struct cleanup *back_to; | |
108546a0 DJ |
223 | const char *base; |
224 | char *dirname; | |
23181151 | 225 | |
108546a0 | 226 | tdesc_str = fetch_xml_from_file (filename, NULL); |
23181151 | 227 | if (tdesc_str == NULL) |
108546a0 DJ |
228 | { |
229 | warning (_("Could not open \"%s\""), filename); | |
230 | return NULL; | |
231 | } | |
23181151 DJ |
232 | |
233 | back_to = make_cleanup (xfree, tdesc_str); | |
108546a0 DJ |
234 | |
235 | /* Simple, portable version of dirname that does not modify its | |
236 | argument. */ | |
237 | base = lbasename (filename); | |
238 | while (base > filename && IS_DIR_SEPARATOR (base[-1])) | |
239 | --base; | |
240 | if (base > filename) | |
241 | { | |
242 | dirname = xmalloc (base - filename + 2); | |
243 | memcpy (dirname, filename, base - filename); | |
244 | ||
245 | /* On DOS based file systems, convert "d:foo" to "d:.", so that | |
246 | we create "d:./bar" later instead of the (different) | |
247 | "d:/bar". */ | |
248 | if (base - filename == 2 && IS_ABSOLUTE_PATH (base) | |
249 | && !IS_DIR_SEPARATOR (filename[0])) | |
250 | dirname[base++ - filename] = '.'; | |
251 | ||
252 | dirname[base - filename] = '\0'; | |
253 | make_cleanup (xfree, dirname); | |
254 | } | |
255 | else | |
256 | dirname = NULL; | |
257 | ||
258 | tdesc = tdesc_parse_xml (tdesc_str, fetch_xml_from_file, dirname); | |
23181151 DJ |
259 | do_cleanups (back_to); |
260 | ||
261 | return tdesc; | |
262 | } | |
263 | ||
108546a0 DJ |
264 | /* Read a string representation of available features from the target, |
265 | using TARGET_OBJECT_AVAILABLE_FEATURES. The returned string is | |
266 | malloc allocated and NUL-terminated. NAME should be a non-NULL | |
267 | string identifying the XML document we want; the top level document | |
268 | is "target.xml". Other calls may be performed for the DTD or | |
269 | for <xi:include>. */ | |
270 | ||
271 | static char * | |
272 | fetch_available_features_from_target (const char *name, void *baton_) | |
273 | { | |
274 | struct target_ops *ops = baton_; | |
275 | ||
276 | /* Read this object as a string. This ensures that a NUL | |
277 | terminator is added. */ | |
278 | return target_read_stralloc (ops, | |
279 | TARGET_OBJECT_AVAILABLE_FEATURES, | |
280 | name); | |
281 | } | |
282 | \f | |
283 | ||
23181151 DJ |
284 | /* Read an XML target description using OPS. Parse it, and return the |
285 | parsed description. */ | |
286 | ||
287 | const struct target_desc * | |
288 | target_read_description_xml (struct target_ops *ops) | |
289 | { | |
290 | struct target_desc *tdesc; | |
291 | char *tdesc_str; | |
292 | struct cleanup *back_to; | |
293 | ||
108546a0 | 294 | tdesc_str = fetch_available_features_from_target ("target.xml", ops); |
23181151 DJ |
295 | if (tdesc_str == NULL) |
296 | return NULL; | |
297 | ||
298 | back_to = make_cleanup (xfree, tdesc_str); | |
108546a0 DJ |
299 | tdesc = tdesc_parse_xml (tdesc_str, |
300 | fetch_available_features_from_target, | |
301 | ops); | |
23181151 DJ |
302 | do_cleanups (back_to); |
303 | ||
304 | return tdesc; | |
305 | } |