* Makefile.in (eval.o): Update dependencies.
[deliverable/binutils-gdb.git] / gdb / memory-map.c
CommitLineData
fd79ecee
DJ
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
32VEC(mem_region_s) *
33parse_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"
fd79ecee 50
dbc981de 51#include "gdb_expat.h"
f2d483c4 52
fd79ecee
DJ
53/* Internal parsing data passed to all Expat callbacks. */
54struct 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
63static void
64free_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
82static void
83memory_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
132static void
133memory_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 {
0cb31fdf
MK
144 char *end = NULL;
145
fd79ecee
DJ
146 if (!data->character_data)
147 throw_error (XML_PARSE_ERROR,
148 _("Empty content of 'property' element"));
fd79ecee
DJ
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. */
184static void
185memory_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
213static void
214clear_result (void *p)
215{
216 VEC(mem_region_s) **result = p;
217 VEC_free (mem_region_s, *result);
218 *result = NULL;
219}
220
221VEC(mem_region_s) *
222parse_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 */
This page took 0.051931 seconds and 4 git commands to generate.