gdb/
[external/binutils.git] / gdb / memory-map.c
1 /* Routines for handling XML memory maps provided by target.
2
3    Copyright (C) 2006
4    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 2 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, write to the Free Software
20    Foundation, Inc., 51 Franklin Street, Fifth Floor,
21    Boston, MA 02110-1301, USA.  */
22
23 #include "defs.h"
24 #include "memory-map.h"
25 #include "gdb_assert.h"
26 #include "exceptions.h"
27
28 #include "gdb_string.h"
29
30 #if !defined(HAVE_LIBEXPAT)
31
32 VEC(mem_region_s) *
33 parse_memory_map (const char *memory_map)
34 {
35   static int have_warned;
36
37   if (!have_warned)
38     {
39       have_warned = 1;
40       warning (_("Can not parse XML memory map; XML support was disabled "
41                  "at compile time"));
42     }
43
44   return NULL;
45 }
46
47 #else /* HAVE_LIBEXPAT */
48
49 #include "xml-support.h"
50 #include <expat.h>
51
52 /* Internal parsing data passed to all Expat callbacks.  */
53 struct memory_map_parsing_data
54   {
55     VEC(mem_region_s) **memory_map;
56     struct mem_region *currently_parsing;
57     char *character_data;
58     const char *property_name;
59     int capture_text;
60   };
61
62 static void
63 free_memory_map_parsing_data (void *p_)
64 {
65   struct memory_map_parsing_data *p = p_;
66
67   xfree (p->character_data);
68 }
69
70 /* Callback called by Expat on start of element.
71    DATA_ is pointer to memory_map_parsing_data
72    NAME is the name of element
73    ATTRS is the zero-terminated array of attribute names and
74    attribute values.
75
76    This function handles the following elements:
77    - 'memory' -- creates a new memory region and initializes it
78      from attributes.  Sets DATA_.currently_parsing to the new region.
79    - 'properties' -- sets DATA.capture_text.  */
80
81 static void
82 memory_map_start_element (void *data_, const XML_Char *name,
83                           const XML_Char **attrs)
84 {
85   static const XML_Char *type_names[] = {"ram", "rom", "flash", 0};
86   static int type_values[] = { MEM_RW, MEM_RO, MEM_FLASH };
87   struct memory_map_parsing_data *data = data_;
88   struct gdb_exception ex;
89
90   TRY_CATCH (ex, RETURN_MASK_ERROR)
91     {
92       if (strcmp (name, "memory") == 0)
93         {
94           struct mem_region *r;
95
96           r = VEC_safe_push (mem_region_s, *data->memory_map, NULL);
97           mem_region_init (r);
98
99           r->lo = xml_get_integer_attribute (attrs, "start");
100           r->hi = r->lo + xml_get_integer_attribute (attrs, "length");
101           r->attrib.mode = xml_get_enum_value (attrs, "type", type_names,
102                                                type_values);
103           r->attrib.blocksize = -1;
104
105           data->currently_parsing = r;
106         }
107       else if (strcmp (name, "property") == 0)
108         {
109           if (!data->currently_parsing)
110             throw_error (XML_PARSE_ERROR,
111                 _("memory map: found 'property' element outside 'memory'"));
112
113           data->capture_text = 1;
114
115           data->property_name = xml_get_required_attribute (attrs, "name");
116         }
117     }
118   if (ex.reason < 0)
119     throw_error
120       (ex.error, _("While parsing element %s:\n%s"), name, ex.message);
121 }
122
123 /* Callback called by Expat on start of element.  DATA_ is a pointer
124    to our memory_map_parsing_data.  NAME is the name of the element.
125
126    This function handles the following elements:
127    - 'property' -- check that the property name is 'blocksize' and
128      sets DATA->currently_parsing->attrib.blocksize
129    - 'memory' verifies that flash block size is set.  */
130
131 static void
132 memory_map_end_element (void *data_, const XML_Char *name)
133 {
134   struct memory_map_parsing_data *data = data_;
135   struct gdb_exception ex;
136
137   TRY_CATCH (ex, RETURN_MASK_ERROR)
138     {
139       if (strcmp (name, "property") == 0)
140         {
141           if (strcmp (data->property_name, "blocksize") == 0)
142             {
143               if (!data->character_data)
144                 throw_error (XML_PARSE_ERROR,
145                              _("Empty content of 'property' element"));
146               char *end = NULL;
147               data->currently_parsing->attrib.blocksize
148                 = strtoul (data->character_data, &end, 0);
149               if (*end != '\0')
150                 throw_error (XML_PARSE_ERROR,
151                              _("Invalid content of the 'blocksize' property"));
152             }
153           else
154             throw_error (XML_PARSE_ERROR,
155                          _("Unknown memory region property: %s"), name);
156
157           data->capture_text = 0;
158         }
159       else if (strcmp (name, "memory") == 0)
160         {
161           if (data->currently_parsing->attrib.mode == MEM_FLASH
162               && data->currently_parsing->attrib.blocksize == -1)
163             throw_error (XML_PARSE_ERROR,
164                          _("Flash block size is not set"));
165
166           data->currently_parsing = 0;
167           data->character_data = 0;
168         }
169     }
170   if (ex.reason < 0)
171     throw_error
172       (ex.error, _("while parsing element %s: \n%s"), name, ex.message);
173 }
174
175 /* Callback called by expat for all character data blocks.
176    DATA_ is the pointer to memory_map_parsing_data.
177    S is the point to character data.
178    LEN is the length of data; the data is not zero-terminated.
179
180    If DATA_->CAPTURE_TEXT is 1, appends this block of characters
181    to DATA_->CHARACTER_DATA.  */
182 static void
183 memory_map_character_data (void *data_, const XML_Char *s,
184                            int len)
185 {
186   struct memory_map_parsing_data *data = data_;
187   int current_size = 0;
188
189   if (!data->capture_text)
190     return;
191
192   /* Expat interface does not guarantee that a single call to
193      a handler will be made. Actually, one call for each line
194      will be made, and character data can possibly span several
195      lines.
196
197      Take care to realloc the data if needed.  */
198   if (!data->character_data)
199     data->character_data = xmalloc (len + 1);
200   else
201     {
202       current_size = strlen (data->character_data);
203       data->character_data = xrealloc (data->character_data,
204                                        current_size + len + 1);
205     }
206
207   memcpy (data->character_data + current_size, s, len);
208   data->character_data[current_size + len] = '\0';
209 }
210
211 static void
212 clear_result (void *p)
213 {
214   VEC(mem_region_s) **result = p;
215   VEC_free (mem_region_s, *result);
216   *result = NULL;
217 }
218
219 VEC(mem_region_s) *
220 parse_memory_map (const char *memory_map)
221 {
222   VEC(mem_region_s) *result = NULL;
223   struct cleanup *back_to = make_cleanup (null_cleanup, NULL);
224   struct cleanup *before_deleting_result;
225   struct cleanup *saved;
226   volatile struct gdb_exception ex;
227   int ok = 0;
228
229   struct memory_map_parsing_data data = {};
230
231   XML_Parser parser = XML_ParserCreateNS (NULL, '!');
232   if (parser == NULL)
233     goto out;
234
235   make_cleanup_free_xml_parser (parser);
236   make_cleanup (free_memory_map_parsing_data, &data);
237   /* Note: 'clear_result' will zero 'result'.  */
238   before_deleting_result = make_cleanup (clear_result, &result);
239
240   XML_SetElementHandler (parser, memory_map_start_element,
241                          memory_map_end_element);
242   XML_SetCharacterDataHandler (parser, memory_map_character_data);
243   XML_SetUserData (parser, &data);
244   data.memory_map = &result;
245
246   TRY_CATCH (ex, RETURN_MASK_ERROR)
247     {
248       if (XML_Parse (parser, memory_map, strlen (memory_map), 1)
249           != XML_STATUS_OK)
250         {
251           enum XML_Error err = XML_GetErrorCode (parser);
252
253           throw_error (XML_PARSE_ERROR, "%s", XML_ErrorString (err));
254         }
255     }
256   if (ex.reason != GDB_NO_ERROR)
257     {
258       if (ex.error == XML_PARSE_ERROR)
259         /* Just report it.  */
260         warning (_("Could not parse XML memory map: %s"), ex.message);
261       else
262         throw_exception (ex);
263     }
264   else
265     /* Parsed successfully, don't need to delete the result.  */
266     discard_cleanups (before_deleting_result);
267
268  out:
269   do_cleanups (back_to);
270   return result;
271 }
272
273 #endif /* HAVE_LIBEXPAT */