* Makefile.in (gdb_expat_h): New.
[deliverable/binutils-gdb.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 */
This page took 0.062925 seconds and 4 git commands to generate.