1/* Routines for handling XML memory maps provided by target.
2
3   Copyright (C) 2006, 2007 Free Software Foundation, Inc.
4
5   This file is part of GDB.
6
7   This program is free software; you can redistribute it and/or modify
8   it under the terms of the GNU General Public License as published by
9   the Free Software Foundation; either version 3 of the License, or
10   (at your option) any later version.
11
12   This program is distributed in the hope that it will be useful,
13   but WITHOUT ANY WARRANTY; without even the implied warranty of
14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15   GNU General Public License for more details.
16
17   You should have received a copy of the GNU General Public License
18   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
19
20#include "defs.h"
21#include "memory-map.h"
22#include "gdb_assert.h"
23#include "exceptions.h"
24
25#include "gdb_string.h"
26
27#if !defined(HAVE_LIBEXPAT)
28
29VEC(mem_region_s) *
30parse_memory_map (const char *memory_map)
31{
32  static int have_warned;
33
34  if (!have_warned)
35    {
36      have_warned = 1;
37      warning (_("Can not parse XML memory map; XML support was disabled "
38		 "at compile time"));
39    }
40
41  return NULL;
42}
43
44#else /* HAVE_LIBEXPAT */
45
46#include "xml-support.h"
47
48/* Internal parsing data passed to all XML callbacks.  */
49struct memory_map_parsing_data
50  {
51    VEC(mem_region_s) **memory_map;
52    char property_name[32];
53  };
54
55/* Handle the start of a <memory> element.  */
56
57static void
58memory_map_start_memory (struct gdb_xml_parser *parser,
59			 const struct gdb_xml_element *element,
60			 void *user_data, VEC(gdb_xml_value_s) *attributes)
61{
62  struct memory_map_parsing_data *data = user_data;
63  struct mem_region *r = VEC_safe_push (mem_region_s, *data->memory_map, NULL);
64  ULONGEST *start_p, *length_p, *type_p;
65
66  start_p = VEC_index (gdb_xml_value_s, attributes, 0)->value;
67  length_p = VEC_index (gdb_xml_value_s, attributes, 1)->value;
68  type_p = VEC_index (gdb_xml_value_s, attributes, 2)->value;
69
70  mem_region_init (r);
71  r->lo = *start_p;
72  r->hi = r->lo + *length_p;
73  r->attrib.mode = *type_p;
74  r->attrib.blocksize = -1;
75}
76
77/* Handle the end of a <memory> element.  Verify that any necessary
78   children were present.  */
79
80static void
81memory_map_end_memory (struct gdb_xml_parser *parser,
82		       const struct gdb_xml_element *element,
83		       void *user_data, const char *body_text)
84{
85  struct memory_map_parsing_data *data = user_data;
86  struct mem_region *r = VEC_last (mem_region_s, *data->memory_map);
87
88  if (r->attrib.mode == MEM_FLASH && r->attrib.blocksize == -1)
89    gdb_xml_error (parser, _("Flash block size is not set"));
90}
91
92/* Handle the start of a <property> element by saving the name
93   attribute for later.  */
94
95static void
96memory_map_start_property (struct gdb_xml_parser *parser,
97			   const struct gdb_xml_element *element,
98			   void *user_data, VEC(gdb_xml_value_s) *attributes)
99{
100  struct memory_map_parsing_data *data = user_data;
101  char *name;
102
103  name = VEC_index (gdb_xml_value_s, attributes, 0)->value;
104  snprintf (data->property_name, sizeof (data->property_name), "%s", name);
105}
106
107/* Handle the end of a <property> element and its value.  */
108
109static void
110memory_map_end_property (struct gdb_xml_parser *parser,
111			 const struct gdb_xml_element *element,
112			 void *user_data, const char *body_text)
113{
114  struct memory_map_parsing_data *data = user_data;
115  char *name = data->property_name;
116
117  if (strcmp (name, "blocksize") == 0)
118    {
119      struct mem_region *r = VEC_last (mem_region_s, *data->memory_map);
120
121      r->attrib.blocksize = gdb_xml_parse_ulongest (parser, body_text);
122    }
123  else
124    gdb_xml_debug (parser, _("Unknown property \"%s\""), name);
125}
126
127/* Discard the constructed memory map (if an error occurs).  */
128
129static void
130clear_result (void *p)
131{
132  VEC(mem_region_s) **result = p;
133  VEC_free (mem_region_s, *result);
134  *result = NULL;
135}
136
137/* The allowed elements and attributes for an XML memory map.  */
138
139const struct gdb_xml_attribute property_attributes[] = {
140  { "name", GDB_XML_AF_NONE, NULL, NULL },
141  { NULL, GDB_XML_AF_NONE, NULL, NULL }
142};
143
144const struct gdb_xml_element memory_children[] = {
145  { "property", property_attributes, NULL,
146    GDB_XML_EF_REPEATABLE | GDB_XML_EF_OPTIONAL,
147    memory_map_start_property, memory_map_end_property },
148  { NULL, NULL, NULL, GDB_XML_EF_NONE, NULL, NULL }
149};
150
151const struct gdb_xml_enum memory_type_enum[] = {
152  { "ram", MEM_RW },
153  { "rom", MEM_RO },
154  { "flash", MEM_FLASH },
155  { NULL, 0 }
156};
157
158const struct gdb_xml_attribute memory_attributes[] = {
159  { "start", GDB_XML_AF_NONE, gdb_xml_parse_attr_ulongest, NULL },
160  { "length", GDB_XML_AF_NONE, gdb_xml_parse_attr_ulongest, NULL },
161  { "type", GDB_XML_AF_NONE, gdb_xml_parse_attr_enum, &memory_type_enum },
162  { NULL, GDB_XML_AF_NONE, NULL, NULL }
163};
164
165const struct gdb_xml_element memory_map_children[] = {
166  { "memory", memory_attributes, memory_children, GDB_XML_EF_REPEATABLE,
167    memory_map_start_memory, memory_map_end_memory },
168  { NULL, NULL, NULL, GDB_XML_EF_NONE, NULL, NULL }
169};
170
171const struct gdb_xml_element memory_map_elements[] = {
172  { "memory-map", NULL, memory_map_children, GDB_XML_EF_NONE,
173    NULL, NULL },
174  { NULL, NULL, NULL, GDB_XML_EF_NONE, NULL, NULL }
175};
176
177VEC(mem_region_s) *
178parse_memory_map (const char *memory_map)
179{
180  struct gdb_xml_parser *parser;
181  VEC(mem_region_s) *result = NULL;
182  struct cleanup *before_deleting_result, *back_to;
183  struct memory_map_parsing_data data = { NULL };
184
185  back_to = make_cleanup (null_cleanup, NULL);
186  parser = gdb_xml_create_parser_and_cleanup (_("target memory map"),
187					      memory_map_elements, &data);
188
189  /* Note: 'clear_result' will zero 'result'.  */
190  before_deleting_result = make_cleanup (clear_result, &result);
191  data.memory_map = &result;
192
193  if (gdb_xml_parse (parser, memory_map) == 0)
194    /* Parsed successfully, don't need to delete the result.  */
195    discard_cleanups (before_deleting_result);
196
197  do_cleanups (back_to);
198  return result;
199}
200
201#endif /* HAVE_LIBEXPAT */
202