/* Routines for handling XML memory maps provided by target.
Copyright (C) 2006, 2007 Free Software Foundation, Inc.
This file is part of GDB.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see . */
#include "defs.h"
#include "memory-map.h"
#include "gdb_assert.h"
#include "exceptions.h"
#include "gdb_string.h"
#if !defined(HAVE_LIBEXPAT)
VEC(mem_region_s) *
parse_memory_map (const char *memory_map)
{
static int have_warned;
if (!have_warned)
{
have_warned = 1;
warning (_("Can not parse XML memory map; XML support was disabled "
"at compile time"));
}
return NULL;
}
#else /* HAVE_LIBEXPAT */
#include "xml-support.h"
/* Internal parsing data passed to all XML callbacks. */
struct memory_map_parsing_data
{
VEC(mem_region_s) **memory_map;
char property_name[32];
};
/* Handle the start of a element. */
static void
memory_map_start_memory (struct gdb_xml_parser *parser,
const struct gdb_xml_element *element,
void *user_data, VEC(gdb_xml_value_s) *attributes)
{
struct memory_map_parsing_data *data = user_data;
struct mem_region *r = VEC_safe_push (mem_region_s, *data->memory_map, NULL);
ULONGEST *start_p, *length_p, *type_p;
start_p = VEC_index (gdb_xml_value_s, attributes, 0)->value;
length_p = VEC_index (gdb_xml_value_s, attributes, 1)->value;
type_p = VEC_index (gdb_xml_value_s, attributes, 2)->value;
mem_region_init (r);
r->lo = *start_p;
r->hi = r->lo + *length_p;
r->attrib.mode = *type_p;
r->attrib.blocksize = -1;
}
/* Handle the end of a element. Verify that any necessary
children were present. */
static void
memory_map_end_memory (struct gdb_xml_parser *parser,
const struct gdb_xml_element *element,
void *user_data, const char *body_text)
{
struct memory_map_parsing_data *data = user_data;
struct mem_region *r = VEC_last (mem_region_s, *data->memory_map);
if (r->attrib.mode == MEM_FLASH && r->attrib.blocksize == -1)
gdb_xml_error (parser, _("Flash block size is not set"));
}
/* Handle the start of a element by saving the name
attribute for later. */
static void
memory_map_start_property (struct gdb_xml_parser *parser,
const struct gdb_xml_element *element,
void *user_data, VEC(gdb_xml_value_s) *attributes)
{
struct memory_map_parsing_data *data = user_data;
char *name;
name = VEC_index (gdb_xml_value_s, attributes, 0)->value;
snprintf (data->property_name, sizeof (data->property_name), "%s", name);
}
/* Handle the end of a element and its value. */
static void
memory_map_end_property (struct gdb_xml_parser *parser,
const struct gdb_xml_element *element,
void *user_data, const char *body_text)
{
struct memory_map_parsing_data *data = user_data;
char *name = data->property_name;
if (strcmp (name, "blocksize") == 0)
{
struct mem_region *r = VEC_last (mem_region_s, *data->memory_map);
r->attrib.blocksize = gdb_xml_parse_ulongest (parser, body_text);
}
else
gdb_xml_debug (parser, _("Unknown property \"%s\""), name);
}
/* Discard the constructed memory map (if an error occurs). */
static void
clear_result (void *p)
{
VEC(mem_region_s) **result = p;
VEC_free (mem_region_s, *result);
*result = NULL;
}
/* The allowed elements and attributes for an XML memory map. */
const struct gdb_xml_attribute property_attributes[] = {
{ "name", GDB_XML_AF_NONE, NULL, NULL },
{ NULL, GDB_XML_AF_NONE, NULL, NULL }
};
const struct gdb_xml_element memory_children[] = {
{ "property", property_attributes, NULL,
GDB_XML_EF_REPEATABLE | GDB_XML_EF_OPTIONAL,
memory_map_start_property, memory_map_end_property },
{ NULL, NULL, NULL, GDB_XML_EF_NONE, NULL, NULL }
};
const struct gdb_xml_enum memory_type_enum[] = {
{ "ram", MEM_RW },
{ "rom", MEM_RO },
{ "flash", MEM_FLASH },
{ NULL, 0 }
};
const struct gdb_xml_attribute memory_attributes[] = {
{ "start", GDB_XML_AF_NONE, gdb_xml_parse_attr_ulongest, NULL },
{ "length", GDB_XML_AF_NONE, gdb_xml_parse_attr_ulongest, NULL },
{ "type", GDB_XML_AF_NONE, gdb_xml_parse_attr_enum, &memory_type_enum },
{ NULL, GDB_XML_AF_NONE, NULL, NULL }
};
const struct gdb_xml_element memory_map_children[] = {
{ "memory", memory_attributes, memory_children, GDB_XML_EF_REPEATABLE,
memory_map_start_memory, memory_map_end_memory },
{ NULL, NULL, NULL, GDB_XML_EF_NONE, NULL, NULL }
};
const struct gdb_xml_element memory_map_elements[] = {
{ "memory-map", NULL, memory_map_children, GDB_XML_EF_NONE,
NULL, NULL },
{ NULL, NULL, NULL, GDB_XML_EF_NONE, NULL, NULL }
};
VEC(mem_region_s) *
parse_memory_map (const char *memory_map)
{
struct gdb_xml_parser *parser;
VEC(mem_region_s) *result = NULL;
struct cleanup *before_deleting_result, *back_to;
struct memory_map_parsing_data data = {};
back_to = make_cleanup (null_cleanup, NULL);
parser = gdb_xml_create_parser_and_cleanup (_("target memory map"),
memory_map_elements, &data);
/* Note: 'clear_result' will zero 'result'. */
before_deleting_result = make_cleanup (clear_result, &result);
data.memory_map = &result;
if (gdb_xml_parse (parser, memory_map) == 0)
/* Parsed successfully, don't need to delete the result. */
discard_cleanups (before_deleting_result);
do_cleanups (back_to);
return result;
}
#endif /* HAVE_LIBEXPAT */