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