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