* memory-map.c (memory_map_end_element): Move variable
[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               char *end = NULL;
145
146               if (!data->character_data)
147                 throw_error (XML_PARSE_ERROR,
148                              _("Empty content of 'property' element"));
149               data->currently_parsing->attrib.blocksize
150                 = strtoul (data->character_data, &end, 0);
151               if (*end != '\0')
152                 throw_error (XML_PARSE_ERROR,
153                              _("Invalid content of the 'blocksize' property"));
154             }
155           else
156             throw_error (XML_PARSE_ERROR,
157                          _("Unknown memory region property: %s"), name);
158
159           data->capture_text = 0;
160         }
161       else if (strcmp (name, "memory") == 0)
162         {
163           if (data->currently_parsing->attrib.mode == MEM_FLASH
164               && data->currently_parsing->attrib.blocksize == -1)
165             throw_error (XML_PARSE_ERROR,
166                          _("Flash block size is not set"));
167
168           data->currently_parsing = 0;
169           data->character_data = 0;
170         }
171     }
172   if (ex.reason < 0)
173     throw_error
174       (ex.error, _("while parsing element %s: \n%s"), name, ex.message);
175 }
176
177 /* Callback called by expat for all character data blocks.
178    DATA_ is the pointer to memory_map_parsing_data.
179    S is the point to character data.
180    LEN is the length of data; the data is not zero-terminated.
181
182    If DATA_->CAPTURE_TEXT is 1, appends this block of characters
183    to DATA_->CHARACTER_DATA.  */
184 static void
185 memory_map_character_data (void *data_, const XML_Char *s,
186                            int len)
187 {
188   struct memory_map_parsing_data *data = data_;
189   int current_size = 0;
190
191   if (!data->capture_text)
192     return;
193
194   /* Expat interface does not guarantee that a single call to
195      a handler will be made. Actually, one call for each line
196      will be made, and character data can possibly span several
197      lines.
198
199      Take care to realloc the data if needed.  */
200   if (!data->character_data)
201     data->character_data = xmalloc (len + 1);
202   else
203     {
204       current_size = strlen (data->character_data);
205       data->character_data = xrealloc (data->character_data,
206                                        current_size + len + 1);
207     }
208
209   memcpy (data->character_data + current_size, s, len);
210   data->character_data[current_size + len] = '\0';
211 }
212
213 static void
214 clear_result (void *p)
215 {
216   VEC(mem_region_s) **result = p;
217   VEC_free (mem_region_s, *result);
218   *result = NULL;
219 }
220
221 VEC(mem_region_s) *
222 parse_memory_map (const char *memory_map)
223 {
224   VEC(mem_region_s) *result = NULL;
225   struct cleanup *back_to = make_cleanup (null_cleanup, NULL);
226   struct cleanup *before_deleting_result;
227   struct cleanup *saved;
228   volatile struct gdb_exception ex;
229   int ok = 0;
230
231   struct memory_map_parsing_data data = {};
232
233   XML_Parser parser = XML_ParserCreateNS (NULL, '!');
234   if (parser == NULL)
235     goto out;
236
237   make_cleanup_free_xml_parser (parser);
238   make_cleanup (free_memory_map_parsing_data, &data);
239   /* Note: 'clear_result' will zero 'result'.  */
240   before_deleting_result = make_cleanup (clear_result, &result);
241
242   XML_SetElementHandler (parser, memory_map_start_element,
243                          memory_map_end_element);
244   XML_SetCharacterDataHandler (parser, memory_map_character_data);
245   XML_SetUserData (parser, &data);
246   data.memory_map = &result;
247
248   TRY_CATCH (ex, RETURN_MASK_ERROR)
249     {
250       if (XML_Parse (parser, memory_map, strlen (memory_map), 1)
251           != XML_STATUS_OK)
252         {
253           enum XML_Error err = XML_GetErrorCode (parser);
254
255           throw_error (XML_PARSE_ERROR, "%s", XML_ErrorString (err));
256         }
257     }
258   if (ex.reason != GDB_NO_ERROR)
259     {
260       if (ex.error == XML_PARSE_ERROR)
261         /* Just report it.  */
262         warning (_("Could not parse XML memory map: %s"), ex.message);
263       else
264         throw_exception (ex);
265     }
266   else
267     /* Parsed successfully, don't need to delete the result.  */
268     discard_cleanups (before_deleting_result);
269
270  out:
271   do_cleanups (back_to);
272   return result;
273 }
274
275 #endif /* HAVE_LIBEXPAT */