* xml-tdesc.c (struct tdesc_xml_cache, tdesc_xml_cache_s)
[platform/upstream/binutils.git] / gdb / xml-tdesc.c
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
31 #include "filenames.h"
32
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 *
41 tdesc_parse_xml (const char *document, xml_fetch_another fetcher,
42                  void *fetcher_baton)
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 /* A record of every XML description we have parsed.  We never discard
59    old descriptions, because we never discard gdbarches.  As long as we
60    have a gdbarch referencing this description, we want to have a copy
61    of it here, so that if we parse the same XML document again we can
62    return the same "struct target_desc *"; if they are not singletons,
63    then we will create unnecessary duplicate gdbarches.  See
64    gdbarch_list_lookup_by_info.  */
65
66 struct tdesc_xml_cache
67 {
68   const char *xml_document;
69   struct target_desc *tdesc;
70 };
71 typedef struct tdesc_xml_cache tdesc_xml_cache_s;
72 DEF_VEC_O(tdesc_xml_cache_s);
73
74 static VEC(tdesc_xml_cache_s) *xml_cache;
75
76 /* Callback data for target description parsing.  */
77
78 struct tdesc_parsing_data
79 {
80   /* The target description we are building.  */
81   struct target_desc *tdesc;
82 };
83
84 /* Handle the end of an <architecture> element and its value.  */
85
86 static void
87 tdesc_end_arch (struct gdb_xml_parser *parser,
88                 const struct gdb_xml_element *element,
89                 void *user_data, const char *body_text)
90 {
91   struct tdesc_parsing_data *data = user_data;
92   const struct bfd_arch_info *arch;
93
94   arch = bfd_scan_arch (body_text);
95   if (arch == NULL)
96     gdb_xml_error (parser, _("Target description specified unknown "
97                              "architecture \"%s\""), body_text);
98   set_tdesc_architecture (data->tdesc, arch);
99 }
100
101 /* The elements and attributes of an XML target description.  */
102
103 const struct gdb_xml_element target_children[] = {
104   { "architecture", NULL, NULL, GDB_XML_EF_OPTIONAL,
105     NULL, tdesc_end_arch },
106   { NULL, NULL, NULL, GDB_XML_EF_NONE, NULL, NULL }
107 };
108
109 const struct gdb_xml_element tdesc_elements[] = {
110   { "target", NULL, target_children, GDB_XML_EF_NONE,
111     NULL, NULL },
112   { NULL, NULL, NULL, GDB_XML_EF_NONE, NULL, NULL }
113 };
114
115 /* Parse DOCUMENT into a target description and return it.  */
116
117 static struct target_desc *
118 tdesc_parse_xml (const char *document, xml_fetch_another fetcher,
119                  void *fetcher_baton)
120 {
121   struct cleanup *back_to, *result_cleanup;
122   struct gdb_xml_parser *parser;
123   struct tdesc_parsing_data data;
124   struct tdesc_xml_cache *cache;
125   char *expanded_text;
126   int ix;
127
128   /* Expand all XInclude directives.  */
129   expanded_text = xml_process_xincludes (_("target description"),
130                                          document, fetcher, fetcher_baton, 0);
131   if (expanded_text == NULL)
132     {
133       warning (_("Could not load XML target description; ignoring"));
134       return NULL;
135     }
136
137   /* Check for an exact match in the list of descriptions we have
138      previously parsed.  strcmp is a slightly inefficient way to
139      do this; an SHA-1 checksum would work as well.  */
140   for (ix = 0; VEC_iterate (tdesc_xml_cache_s, xml_cache, ix, cache); ix++)
141     if (strcmp (cache->xml_document, expanded_text) == 0)
142       {
143        xfree (expanded_text);
144        return cache->tdesc;
145       }
146
147   back_to = make_cleanup (null_cleanup, NULL);
148   parser = gdb_xml_create_parser_and_cleanup (_("target description"),
149                                               tdesc_elements, &data);
150   gdb_xml_use_dtd (parser, "gdb-target.dtd");
151
152   memset (&data, 0, sizeof (struct tdesc_parsing_data));
153   data.tdesc = allocate_target_description ();
154   result_cleanup = make_cleanup_free_target_description (data.tdesc);
155   make_cleanup (xfree, expanded_text);
156
157   if (gdb_xml_parse (parser, expanded_text) == 0)
158     {
159       /* Parsed successfully.  */
160       struct tdesc_xml_cache new_cache;
161
162       new_cache.xml_document = expanded_text;
163       new_cache.tdesc = data.tdesc;
164       VEC_safe_push (tdesc_xml_cache_s, xml_cache, &new_cache);
165       discard_cleanups (result_cleanup);
166       do_cleanups (back_to);
167       return data.tdesc;
168     }
169   else
170     {
171       warning (_("Could not load XML target description; ignoring"));
172       do_cleanups (back_to);
173       return NULL;
174     }
175 }
176 #endif /* HAVE_LIBEXPAT */
177 \f
178
179 /* Close FILE.  */
180
181 static void
182 do_cleanup_fclose (void *file)
183 {
184   fclose (file);
185 }
186
187 /* Open FILENAME, read all its text into memory, close it, and return
188    the text.  If something goes wrong, return NULL and warn.  */
189
190 static char *
191 fetch_xml_from_file (const char *filename, void *baton)
192 {
193   const char *dirname = baton;
194   FILE *file;
195   struct cleanup *back_to;
196   char *text;
197   size_t len, offset;
198
199   if (dirname && *dirname)
200     {
201       char *fullname = concat (dirname, "/", filename, NULL);
202       if (fullname == NULL)
203         nomem (0);
204       file = fopen (fullname, FOPEN_RT);
205       xfree (fullname);
206     }
207   else
208     file = fopen (filename, FOPEN_RT);
209
210   if (file == NULL)
211     return NULL;
212
213   back_to = make_cleanup (do_cleanup_fclose, file);
214
215   /* Read in the whole file, one chunk at a time.  */
216   len = 4096;
217   offset = 0;
218   text = xmalloc (len);
219   make_cleanup (free_current_contents, &text);
220   while (1)
221     {
222       size_t bytes_read;
223
224       /* Continue reading where the last read left off.  Leave at least
225          one byte so that we can NUL-terminate the result.  */
226       bytes_read = fread (text + offset, 1, len - offset - 1, file);
227       if (ferror (file))
228         {
229           warning (_("Read error from \"%s\""), filename);
230           do_cleanups (back_to);
231           return NULL;
232         }
233
234       offset += bytes_read;
235
236       if (feof (file))
237         break;
238
239       len = len * 2;
240       text = xrealloc (text, len);
241     }
242
243   fclose (file);
244   discard_cleanups (back_to);
245
246   text[offset] = '\0';
247   return text;
248 }
249
250 /* Read an XML target description from FILENAME.  Parse it, and return
251    the parsed description.  */
252
253 const struct target_desc *
254 file_read_description_xml (const char *filename)
255 {
256   struct target_desc *tdesc;
257   char *tdesc_str;
258   struct cleanup *back_to;
259   const char *base;
260   char *dirname;
261
262   tdesc_str = fetch_xml_from_file (filename, NULL);
263   if (tdesc_str == NULL)
264     {
265       warning (_("Could not open \"%s\""), filename);
266       return NULL;
267     }
268
269   back_to = make_cleanup (xfree, tdesc_str);
270
271   /* Simple, portable version of dirname that does not modify its
272      argument.  */
273   base = lbasename (filename);
274   while (base > filename && IS_DIR_SEPARATOR (base[-1]))
275     --base;
276   if (base > filename)
277     {
278       dirname = xmalloc (base - filename + 2);
279       memcpy (dirname, filename, base - filename);
280
281       /* On DOS based file systems, convert "d:foo" to "d:.", so that
282          we create "d:./bar" later instead of the (different)
283          "d:/bar".  */
284       if (base - filename == 2 && IS_ABSOLUTE_PATH (base)
285           && !IS_DIR_SEPARATOR (filename[0]))
286         dirname[base++ - filename] = '.';
287
288       dirname[base - filename] = '\0';
289       make_cleanup (xfree, dirname);
290     }
291   else
292     dirname = NULL;
293
294   tdesc = tdesc_parse_xml (tdesc_str, fetch_xml_from_file, dirname);
295   do_cleanups (back_to);
296
297   return tdesc;
298 }
299
300 /* Read a string representation of available features from the target,
301    using TARGET_OBJECT_AVAILABLE_FEATURES.  The returned string is
302    malloc allocated and NUL-terminated.  NAME should be a non-NULL
303    string identifying the XML document we want; the top level document
304    is "target.xml".  Other calls may be performed for the DTD or
305    for <xi:include>.  */
306
307 static char *
308 fetch_available_features_from_target (const char *name, void *baton_)
309 {
310   struct target_ops *ops = baton_;
311
312   /* Read this object as a string.  This ensures that a NUL
313      terminator is added.  */
314   return target_read_stralloc (ops,
315                                TARGET_OBJECT_AVAILABLE_FEATURES,
316                                name);
317 }
318 \f
319
320 /* Read an XML target description using OPS.  Parse it, and return the
321    parsed description.  */
322
323 const struct target_desc *
324 target_read_description_xml (struct target_ops *ops)
325 {
326   struct target_desc *tdesc;
327   char *tdesc_str;
328   struct cleanup *back_to;
329
330   tdesc_str = fetch_available_features_from_target ("target.xml", ops);
331   if (tdesc_str == NULL)
332     return NULL;
333
334   back_to = make_cleanup (xfree, tdesc_str);
335   tdesc = tdesc_parse_xml (tdesc_str,
336                            fetch_available_features_from_target,
337                            ops);
338   do_cleanups (back_to);
339
340   return tdesc;
341 }