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