This is the mail archive of the
gdb-patches@sourceware.org
mailing list for the GDB project.
Re: Flash support part 1: memory maps
- From: Vladimir Prus <vladimir at codesourcery dot com>
- To: Mark Kettenis <mark dot kettenis at xs4all dot nl>
- Cc: eliz at gnu dot org, gdb-patches at sources dot redhat dot com
- Date: Tue, 1 Aug 2006 09:11:14 +0400
- Subject: Re: Flash support part 1: memory maps
- References: <200607201341.34070.vladimir@codesourcery.com> <200607311720.26487.vladimir@codesourcery.com> <200607312208.k6VM82PM012536@elgar.sibelius.xs4all.nl>
On Tuesday 01 August 2006 02:08, Mark Kettenis wrote:
> > + if (!VEC_empty (memory_region, result))
> > + for (i = 0; i < VEC_length (memory_region, result) - 1; ++i)
> > + {
> > + memory_region *this_one = VEC_index (memory_region,
> > result, i); + memory_region *next_one = VEC_index
> > + (memory_region, result, i+1);
>
> Missing spaces around the '+'.
Ok.
> > === gdb/target.h
> > ==================================================================
> > --- gdb/target.h (/mirrors/gdb) (revision 326)
> > +++ gdb/target.h (/patches/memory_map/gdb) (revision 326)
> > @@ -55,6 +55,8 @@
> > #include "symtab.h"
> > #include "dcache.h"
> > #include "memattr.h"
> > +#include "vec.h"
> > +#include "memory-map.h"
> >
> > enum strata
> > {
> > @@ -194,7 +196,9 @@
> > /* Transfer auxilliary vector. */
> > TARGET_OBJECT_AUXV,
> > /* StackGhost cookie. See "sparc-tdep.c". */
> > - TARGET_OBJECT_WCOOKIE
> > + TARGET_OBJECT_WCOOKIE,
> > + /* Target memory map in XML format. */
> > + TARGET_OBJECT_MEMORY_MAP,
>
> I'm still not sure how this fits in. Certainly if my target already
> provides a memory map in a nice data structure I'm not supposed to
> convert that into XML am I? I should be able to just implement
> to_memory_map and convert it directly into a VEC(memory_region).
Yes. The remote implementation of to_memory_map uses TARGET_OBJECT_MEMORY_MAP,
but implementation for another target is not required to.
> Arghh, I just realize that memory_region is a typedef for struct
> memory_region. I'm not too big a fan of that practice, since I stop
> realizing that it really is a struct and start doing stupid things
> with it...
Well, "struct memory_region" is too long and really a lot of lines will run
out of 80 columns immediately.
> > /* Possible future objects: TARGET_OBJECT_FILE, TARGET_OBJECT_PROC,
> > ... */ };
> > @@ -437,6 +441,20 @@
> > gdb_byte *readbuf, const gdb_byte *writebuf,
> > ULONGEST offset, LONGEST len);
> >
> > + /* Returns the memory map for the target. The return value of 0
> > means + that no memory map is available. If a memory address does
> > not fall + within any returned regions, it's assumed to be RAM.
> > The returned + memory regions should not overlap.
> > +
> > + The order of regions does not matter, as target_memory_map will
> > + sort regions by starting address anyway. For that reason, this
> > + function should not be called directly, only via
> > target_memory_map. +
> > + This method is expected to cache the data if fetching it is slow.
> > + The higher-level code has no way of knowing when memory map
> > + could change, and so can't do caching itself. */
> > + VEC(memory_region) * (*to_memory_map) (struct target_ops *);
>
> That's not a multiplication isn't it? I think you should remove the
> space after that first '*' (indent is too stupid and parses this as a
> binary operator).
Ok.
>
> > +
> > +/* Returns the value of attribute ATTR from expat attribute list ATTRS.
> > + If not found, calls 'error'. */
> > +const XML_Char *xml_get_attribute_value(const XML_Char **attrs,
> > + const XML_Char *attr)
> > +{
>
> const XML_Char *
> xml_get_attr...
>
> > +
> > +int compare_memory_region_starting_address (const void* a, const void
> > *b) +{
> > + ULONGEST a_begin = ((memory_region *)a)->begin;
> > + ULONGEST b_begin = ((memory_region *)b)->begin;
> > + return a_begin - b_begin;
> > +}
>
> int
> compare_memort_region...
OK.
> > === gdb/memory-map.h
> > ==================================================================
> > --- gdb/memory-map.h (/mirrors/gdb) (revision 326)
> > +++ gdb/memory-map.h (/patches/memory_map/gdb) (revision 326)
> > @@ -0,0 +1,142 @@
> > +/* Routines for handling XML memory maps provided by target.
> > +
> > + Copyright (C) 2006
> > + 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 2 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, write to the Free Software
> > + Foundation, Inc., 51 Franklin Street, Fifth Floor,
> > + Boston, MA 02110-1301, USA. */
> > +
> > +
> > +#ifndef MEMORY_MAP_H
> > +#define MEMORY_MAP_H
> > +
> > +#include "vec.h"
> > +
> > +/* Describes various kinds of memory regions. */
> > +enum memory_region_type
> > + {
> > + /* Memory that can be freely written and read. */
> > + TARGET_MEMORY_RAM,
> > + /* Memory that can't be written at all. */
> > + TARGET_MEMORY_ROM,
> > + /* Memory that can be written only using special operations. */
> > + TARGET_MEMORY_FLASH
> > + };
> > +
> > +/* Describes properties of a memory range. */
> > +typedef struct memory_region
> > + {
> > + /* The first address of the region. */
> > + ULONGEST begin;
> > + /* The past-the-end address of the region. */
> > + ULONGEST end;
> > + /* Type of the memory in this region. */
> > + enum memory_region_type memory_type;
> > + /* The size of flash memory sector. Some flash chips have
> > non-uniform + sector sizes, for example small sectors at beginning
> > and end. + In this case gdb will have to have several memory_region
> > objects each + one having uniform sector size.
> > + This field is defined only of MEMORY_TYPE == TARGET_MEMORY_FLASH.
> > */ + unsigned flash_block_size;
> > + } memory_region;
> > +
> > +DEF_VEC_O(memory_region);
> > +
> > +/* Casts both A and B to memory_region, compares they starting addresses
> > + and returns value less than zero, equal to zero, or greater then zero
> > + if A's starting address is less than B's starting address, equal to,
> > + or greater then, respectively. This function is suitable for sorting
> > + vector of memory_regions with the qsort function. */
> > +int compare_memory_region_starting_address (const void* a, const void
> > *b); +
> > +/* Parses XML memory map passed as argument and returns the memory
> > + regions it describes. On any error, emits error message and
> > + returns 0. Does not throw. Ownership of result is passed to the
> > caller. */ +VEC(memory_region) *parse_memory_map (const char
> > *memory_map);
> > +
> > +#endif
> > +/* Routines for handling XML memory maps provided by target.
.....
> You really don't have to say things twice ;-).
Ick. Either "patch" or "svk" is playing tricks on me.
Revised patch attached (changelog unchaged).
- Volodya
=== gdb/target.c
==================================================================
--- gdb/target.c (/mirrors/gdb) (revision 334)
+++ gdb/target.c (/patches/memory_map/gdb) (revision 334)
@@ -456,6 +456,7 @@
INHERIT (to_make_corefile_notes, t);
INHERIT (to_get_thread_local_address, t);
INHERIT (to_magic, t);
+ /* Do not inherit to_memory_map. */
}
#undef INHERIT
@@ -1011,6 +1012,50 @@
return target_xfer_memory (memaddr, bytes, len, 1);
}
+
+VEC(memory_region) *
+target_memory_map (void)
+{
+ struct target_ops *t;
+
+ for (t = current_target.beneath; t != NULL; t = t->beneath)
+ if (t->to_memory_map != NULL)
+ {
+ VEC(memory_region) *result;
+ int i;
+
+ if (targetdebug)
+ fprintf_unfiltered (gdb_stdlog, "target_memory_map\n");
+
+ result = t->to_memory_map (t);
+
+ qsort (VEC_address (memory_region, result),
+ VEC_length (memory_region, result),
+ sizeof (memory_region),
+ compare_memory_region_starting_address);
+
+ /* Check that regions do not overlap. */
+ if (!VEC_empty (memory_region, result))
+ for (i = 0; i < VEC_length (memory_region, result) - 1; ++i)
+ {
+ memory_region *this_one = VEC_index (memory_region, result, i);
+ memory_region *next_one = VEC_index
+ (memory_region, result, i + 1);
+
+ if (this_one->end > next_one->begin)
+ {
+ warning (_("Overlapping regions in memory map: ignoring"));
+ VEC_free (memory_region, result);
+ return 0;
+ }
+ }
+
+ return result;
+ }
+
+ tcomplain ();
+}
+
#ifndef target_stopped_data_address_p
int
target_stopped_data_address_p (struct target_ops *target)
=== gdb/remote.c
==================================================================
--- gdb/remote.c (/mirrors/gdb) (revision 334)
+++ gdb/remote.c (/patches/memory_map/gdb) (revision 334)
@@ -60,6 +60,8 @@
#include "remote-fileio.h"
+#include "memory-map.h"
+
/* The size to align memory write packets, when practical. The protocol
does not guarantee any alignment, and gdb will generate short
writes and unaligned writes, but even as a best-effort attempt this
@@ -233,6 +235,15 @@
a buffer in the stub), this will be set to that packet size.
Otherwise zero, meaning to use the guessed size. */
long explicit_packet_size;
+
+ /* The memory map we've obtained from remote. */
+ VEC(memory_region) *current_memory_map;
+
+ /* Tells if we've already fetched memory map. If non-zero,
+ we don't need to try again. Note that if we've tried to
+ fetch memory map but failed, this field will be non-zero,
+ while CURRENT_MEMORY_MAP will be NULL. */
+ int fetched_memory_map;
};
/* This data could be associated with a target, but we do not always
@@ -349,6 +360,9 @@
rs->buf = xrealloc (rs->buf, rs->buf_size);
}
+ rs->current_memory_map = NULL;
+ rs->fetched_memory_map = 0;
+
return rsa;
}
@@ -826,6 +840,7 @@
PACKET_Z3,
PACKET_Z4,
PACKET_qXfer_auxv,
+ PACKET_qXfer_memory_map,
PACKET_qGetTLSAddr,
PACKET_qSupported,
PACKET_MAX
@@ -2177,7 +2192,9 @@
static struct protocol_feature remote_protocol_features[] = {
{ "PacketSize", PACKET_DISABLE, remote_packet_size, -1 },
{ "qXfer:auxv:read", PACKET_DISABLE, remote_supported_packet,
- PACKET_qXfer_auxv }
+ PACKET_qXfer_auxv },
+ { "qXfer:memory-map:read", PACKET_DISABLE, remote_supported_packet,
+ PACKET_qXfer_memory_map }
};
static void
@@ -2373,6 +2390,11 @@
use_threadinfo_query = 1;
use_threadextra_query = 1;
+ /* After connect, memory map is not valid. */
+ rs->fetched_memory_map = 0;
+ VEC_free (memory_region, rs->current_memory_map);
+ rs->current_memory_map = NULL;
+
/* The first packet we send to the target is the optional "supported
packets" request. If the target can answer this, it will tell us
which later probes to skip. */
@@ -5312,6 +5334,11 @@
return remote_read_qxfer (ops, "auxv", annex, readbuf, offset, len,
&remote_protocol_packets[PACKET_qXfer_auxv]);
+ case TARGET_OBJECT_MEMORY_MAP:
+ gdb_assert (annex == NULL);
+ return remote_read_qxfer (ops, "memory-map", annex, readbuf, offset, len,
+ &remote_protocol_packets[PACKET_qXfer_memory_map]);
+
default:
return -1;
}
@@ -5420,6 +5447,29 @@
}
}
+static VEC(memory_region) *
+remote_memory_map (struct target_ops *ops)
+{
+ struct cleanup *back_to = make_cleanup (null_cleanup, 0);
+ struct remote_state *rs = get_remote_state ();
+
+ if (!rs->fetched_memory_map)
+ {
+ char *text = target_read_stralloc (¤t_target,
+ TARGET_OBJECT_MEMORY_MAP, NULL);
+ if (text)
+ {
+ make_cleanup (free_current_contents, &text);
+
+ rs->fetched_memory_map = 1;
+ rs->current_memory_map = parse_memory_map (text);
+ }
+ }
+
+ do_cleanups (back_to);
+ return rs->current_memory_map;
+}
+
static void
packet_command (char *args, int from_tty)
{
@@ -5692,6 +5742,7 @@
remote_ops.to_has_execution = 1;
remote_ops.to_has_thread_control = tc_schedlock; /* can lock scheduler */
remote_ops.to_magic = OPS_MAGIC;
+ remote_ops.to_memory_map = remote_memory_map;
}
/* Set up the extended remote vector by making a copy of the standard
@@ -5821,6 +5872,7 @@
remote_async_ops.to_async = remote_async;
remote_async_ops.to_async_mask_value = 1;
remote_async_ops.to_magic = OPS_MAGIC;
+ remote_async_ops.to_memory_map = remote_memory_map;
}
/* Set up the async extended remote vector by making a copy of the standard
@@ -6061,6 +6113,9 @@
add_packet_config_cmd (&remote_protocol_packets[PACKET_qXfer_auxv],
"qXfer:auxv:read", "read-aux-vector", 0);
+ add_packet_config_cmd (&remote_protocol_packets[PACKET_qXfer_memory_map],
+ "qXfer:memory-map:read", "memory-map", 0);
+
add_packet_config_cmd (&remote_protocol_packets[PACKET_qGetTLSAddr],
"qGetTLSAddr", "get-thread-local-storage-address",
0);
=== gdb/target.h
==================================================================
--- gdb/target.h (/mirrors/gdb) (revision 334)
+++ gdb/target.h (/patches/memory_map/gdb) (revision 334)
@@ -55,6 +55,8 @@
#include "symtab.h"
#include "dcache.h"
#include "memattr.h"
+#include "vec.h"
+#include "memory-map.h"
enum strata
{
@@ -194,7 +196,9 @@
/* Transfer auxilliary vector. */
TARGET_OBJECT_AUXV,
/* StackGhost cookie. See "sparc-tdep.c". */
- TARGET_OBJECT_WCOOKIE
+ TARGET_OBJECT_WCOOKIE,
+ /* Target memory map in XML format. */
+ TARGET_OBJECT_MEMORY_MAP,
/* Possible future objects: TARGET_OBJECT_FILE, TARGET_OBJECT_PROC, ... */
};
@@ -437,6 +441,20 @@
gdb_byte *readbuf, const gdb_byte *writebuf,
ULONGEST offset, LONGEST len);
+ /* Returns the memory map for the target. The return value of 0 means
+ that no memory map is available. If a memory address does not fall
+ within any returned regions, it's assumed to be RAM. The returned
+ memory regions should not overlap.
+
+ The order of regions does not matter, as target_memory_map will
+ sort regions by starting address anyway. For that reason, this
+ function should not be called directly, only via target_memory_map.
+
+ This method is expected to cache the data if fetching it is slow.
+ The higher-level code has no way of knowing when memory map
+ could change, and so can't do caching itself. */
+ VEC(memory_region) *(*to_memory_map) (struct target_ops *);
+
int to_magic;
/* Need sub-structure for target machine related rather than comm related?
*/
@@ -575,6 +593,12 @@
extern int target_write_memory_partial (CORE_ADDR addr, gdb_byte *buf,
int len, int *err);
+/* Calls the first non-null to_memory_map pointer in target_stack.
+ Sorts the result by starting address and returns it. Additionally
+ checks that memory regions do not overlap. If they do, issues
+ a warning and returns empty vector. */
+VEC(memory_region) *target_memory_map (void);
+
extern char *child_pid_to_exec_file (int);
extern char *child_core_file_to_sym_file (char *);
=== gdb/memory-map.c
==================================================================
--- gdb/memory-map.c (/mirrors/gdb) (revision 334)
+++ gdb/memory-map.c (/patches/memory_map/gdb) (revision 334)
@@ -0,0 +1,365 @@
+/* Routines for handling XML memory maps provided by target.
+
+ Copyright (C) 2006
+ 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 2 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA. */
+
+#include "defs.h"
+#include "memory-map.h"
+#include "gdb_assert.h"
+#include "exceptions.h"
+
+#include <expat.h>
+
+#include "gdb_string.h"
+
+/* Internal parsing data passed to all Expat callbacks. */
+struct memory_map_parsing_data
+ {
+ VEC(memory_region) **memory_map;
+ memory_region *currently_parsed;
+ char *character_data;
+ const char* property_name;
+ int capture_text;
+ };
+
+static void
+free_memory_map_parsing_data (void *p_)
+{
+ struct memory_map_parsing_data *p = p_;
+
+ xfree (p->character_data);
+}
+
+
+/* Returns the value of attribute ATTR from expat attribute list ATTRS.
+ If not found, calls 'error'. */
+const XML_Char *
+xml_get_attribute_value(const XML_Char **attrs,
+ const XML_Char *attr)
+{
+ const XML_Char **p;
+ for (p = attrs; *p; p += 2)
+ {
+ const char *name = p[0];
+ const char *val = p[1];
+
+ if (strcmp (name, attr) == 0)
+ return val;
+ }
+ throw_error (XML_MEMORY_MAP_ERROR, _("Can't find attribute %s"), attr);
+ return 0;
+}
+
+/* Parse a field VALSTR that we expect to contain an integer value.
+ The integer is returned in *VALP.
+ The string is parsed with the strtoul rountine.
+
+ Returns 0 for success, -1 for error. */
+static int
+xml_parse_unsigned_integer (const char *valstr, unsigned long *valp)
+{
+ char *endptr;
+ unsigned result;
+
+ if (*valstr == '\0')
+ return -1;
+
+ result = strtoul (valstr, &endptr, 0);
+ if (*endptr != '\0')
+ return -1;
+
+ *valp = result;
+ return 0;
+}
+
+/* Gets the value of an integer attribute, if it's present.
+ If the attribute is not found, or can't be parsed as integer,
+ calls error. */
+static unsigned long
+xml_get_integer_attribute (const XML_Char **attrs,
+ const XML_Char *attr)
+{
+ unsigned long result;
+ const XML_Char *value = xml_get_attribute_value (attrs, attr);
+
+ if (xml_parse_unsigned_integer (value, &result) != 0)
+ {
+ throw_error (XML_MEMORY_MAP_ERROR,
+ _("Can't convert value of attribute %s, %s, to integer"),
+ attr, value);
+ }
+ return result;
+}
+
+/* Obtains a value of attribute with enumerated type. In XML, enumerated
+ attributes have string as a value, and in C, they are represented as
+ values of enumerated type. This function maps the attribute onto
+ an integer value that can be immediately converted into enumerated
+ type.
+
+ First, obtains the string value of ATTR in ATTRS.
+ Then, finds the index of that value in XML_NAMES, which is a zero-terminated
+ array of strings. If found, returns the element of VALUES with that index.
+ Otherwise throws. */
+static int
+xml_get_enum_value (const XML_Char **attrs,
+ const XML_Char *attr,
+ const XML_Char **xml_names,
+ int *values)
+{
+ const XML_Char *value = xml_get_attribute_value (attrs, attr);
+
+ int i;
+ for (i = 0; xml_names[i]; ++i)
+ {
+ if (strcmp (xml_names[i], value) == 0)
+ return values[i];
+ }
+ throw_error (XML_MEMORY_MAP_ERROR,
+ _("Invalid enumerated value in XML: %s"), value);
+}
+
+/* Callback called by Expat on start of element.
+ DATA_ is pointer to memory_map_parsing_data
+ NAME is the name of element
+ ATTRS is the zero-terminated array of attribute names and
+ attribute values.
+
+ This function handles the following elements:
+ - 'memory' -- creates new memory region and initializes it
+ from attributes. sets DATA_.CURRENTLY_PARSED to the new region.
+ - 'properties' -- sets DATA.CAPTURE_TEXT. */
+static void
+memory_map_start_element (void* data_, const XML_Char *name,
+ const XML_Char **attrs)
+{
+ struct memory_map_parsing_data *data = data_;
+ struct gdb_exception ex;
+
+ TRY_CATCH (ex, RETURN_MASK_ERROR)
+ {
+ if (strcmp (name, "memory") == 0)
+ {
+ struct memory_region *r =
+ VEC_safe_push (memory_region, *data->memory_map, NULL);
+
+ r->begin = xml_get_integer_attribute (attrs, "start");
+ r->end = r->begin + xml_get_integer_attribute (attrs, "length");
+
+ {
+ static const XML_Char* names[] = {"ram", "rom", "flash", 0};
+ static int values[] = {TARGET_MEMORY_RAM, TARGET_MEMORY_ROM,
+ TARGET_MEMORY_FLASH};
+
+ r->memory_type = xml_get_enum_value (attrs, "type", names, values);
+ }
+ r->flash_block_size = (unsigned)-1;
+
+ data->currently_parsed = r;
+ }
+ else if (strcmp (name, "property") == 0)
+ {
+ if (!data->currently_parsed)
+ throw_error (XML_MEMORY_MAP_ERROR,
+ _("memory map: found 'property' element outside 'memory'"));
+
+ data->capture_text = 1;
+
+ data->property_name = xml_get_attribute_value (attrs, "name");
+ }
+ }
+ if (ex.reason < 0)
+ throw_error
+ (ex.error, _("while parsing element %s:\n%s"), name, ex.message);
+
+}
+
+/* Callback called by Expat on start of element.
+ DATA_ is pointer to memory_map_parsing_data
+ NAME is the name of element
+
+ This function handles the following elements:
+ - 'property' -- check that property name is 'blocksize' and
+ sets DATA->CURRENT_PARSED->FLASH_BLOCK_SIZE
+ - 'memory' verifies that flash block size is set. */
+static void
+memory_map_end_element (void* data_, const XML_Char *name)
+{
+ struct memory_map_parsing_data *data = data_;
+ struct gdb_exception ex;
+
+ TRY_CATCH (ex, RETURN_MASK_ERROR)
+ {
+ if (strcmp (name, "property") == 0)
+ {
+ if (strcmp (data->property_name, "blocksize") == 0)
+ {
+ if (!data->character_data)
+ throw_error (XML_MEMORY_MAP_ERROR,
+ _("Empty content of 'property' element"));
+ char *end = 0;
+ data->currently_parsed->flash_block_size =
+ strtoul (data->character_data, &end, 0);
+ if (*end != '\0')
+ throw_error (XML_MEMORY_MAP_ERROR,
+ _("Invalid content of the 'blocksize' property"));
+ }
+ else
+ throw_error (XML_MEMORY_MAP_ERROR,
+ _("Unknown memory region property: %s"), name);
+
+ data->capture_text = 0;
+ }
+ else if (strcmp (name, "memory") == 0)
+ {
+ if (data->currently_parsed->memory_type == TARGET_MEMORY_FLASH
+ && data->currently_parsed->flash_block_size == (unsigned)-1)
+ throw_error (XML_MEMORY_MAP_ERROR,
+ _("Flash block size is not set"));
+
+ data->currently_parsed = 0;
+ data->character_data = 0;
+ }
+ }
+ if (ex.reason < 0)
+ throw_error
+ (ex.error, _("while parsing element %s: \n%s"), name, ex.message);
+}
+
+/* Callback called by expat for all character data blocks.
+ DATA_ is the pointer to memory_map_parsing_data.
+ S is the point to character data.
+ LEN is the length of data; the data is not zero-terminated.
+
+ If DATA_->CAPTURE_TEXT is 1, appends this block of characters
+ to DATA_->CHARACTER_DATA. */
+static void
+memory_map_character_data (void *data_, const XML_Char *s,
+ int len)
+{
+ struct memory_map_parsing_data *data = data_;
+ int current_size = 0;
+
+ if (!data->capture_text)
+ return;
+
+ /* Expat interface does not guarantee that a single call to
+ a handler will be made. Actually, one call for each line
+ will be made, and character data can possibly span several
+ lines.
+
+ Take care to realloc the data if needed. */
+ if (!data->character_data)
+ data->character_data = xmalloc (len + 1);
+ else
+ {
+ current_size = strlen (data->character_data);
+ data->character_data = xrealloc (data->character_data,
+ current_size + len + 1);
+ }
+
+ memcpy (data->character_data + current_size, s, len);
+ data->character_data[current_size + len] = '\0';
+}
+
+static void
+clear_result (void *p)
+{
+ VEC(memory_region) **result = p;
+ VEC_free (memory_region, *result);
+ *result = 0;
+}
+
+static void
+cleanup_XML_parser (void *p)
+{
+ XML_Parser parser = p;
+ XML_ParserFree (parser);
+}
+
+
+VEC(memory_region) *
+parse_memory_map (const char *memory_map)
+{
+ VEC(memory_region) *result = 0;
+ struct cleanup *back_to = make_cleanup (null_cleanup, NULL);
+ struct cleanup *before_deleting_result;
+ struct cleanup *saved;
+ volatile struct gdb_exception ex;
+ int ok = 0;
+
+ struct memory_map_parsing_data data = {};
+
+ XML_Parser parser = XML_ParserCreateNS (NULL, '!');
+ if (parser == NULL)
+ goto out;
+
+ make_cleanup (cleanup_XML_parser, parser);
+ make_cleanup (free_memory_map_parsing_data, &data);
+ /* Note: 'clear_result' will zero 'result'. */
+ before_deleting_result = make_cleanup (clear_result, &result);
+
+
+ XML_SetElementHandler (parser, memory_map_start_element,
+ memory_map_end_element);
+ XML_SetCharacterDataHandler (parser, memory_map_character_data);
+ XML_SetUserData (parser, &data);
+ data.memory_map = &result;
+
+ TRY_CATCH (ex, RETURN_MASK_ERROR)
+ {
+ if (XML_Parse (parser, memory_map, strlen (memory_map), 1)
+ != XML_STATUS_OK)
+ {
+ enum XML_Error err = XML_GetErrorCode (parser);
+
+ throw_error (XML_MEMORY_MAP_ERROR, "%s", XML_ErrorString (err));
+ }
+ }
+ if (ex.reason != GDB_NO_ERROR)
+ {
+ if (ex.error == XML_MEMORY_MAP_ERROR)
+ {
+ /* Just report it. */
+ warning (_("Could not parse XML memory map: %s"), ex.message);
+ }
+ else
+ {
+ throw_exception (ex);
+ }
+ }
+ else
+ {
+ /* Parsed successfully, don't need to delete result. */
+ discard_cleanups (before_deleting_result);
+ }
+
+ out:
+ do_cleanups (back_to);
+ return result;
+}
+
+int
+compare_memory_region_starting_address (const void* a, const void *b)
+{
+ ULONGEST a_begin = ((memory_region *)a)->begin;
+ ULONGEST b_begin = ((memory_region *)b)->begin;
+ return a_begin - b_begin;
+}
=== gdb/memory-map.h
==================================================================
--- gdb/memory-map.h (/mirrors/gdb) (revision 334)
+++ gdb/memory-map.h (/patches/memory_map/gdb) (revision 334)
@@ -0,0 +1,71 @@
+/* Routines for handling XML memory maps provided by target.
+
+ Copyright (C) 2006
+ 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 2 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA. */
+
+
+#ifndef MEMORY_MAP_H
+#define MEMORY_MAP_H
+
+#include "vec.h"
+
+/* Describes various kinds of memory regions. */
+enum memory_region_type
+ {
+ /* Memory that can be freely written and read. */
+ TARGET_MEMORY_RAM,
+ /* Memory that can't be written at all. */
+ TARGET_MEMORY_ROM,
+ /* Memory that can be written only using special operations. */
+ TARGET_MEMORY_FLASH
+ };
+
+/* Describes properties of a memory range. */
+typedef struct memory_region
+ {
+ /* The first address of the region. */
+ ULONGEST begin;
+ /* The past-the-end address of the region. */
+ ULONGEST end;
+ /* Type of the memory in this region. */
+ enum memory_region_type memory_type;
+ /* The size of flash memory sector. Some flash chips have non-uniform
+ sector sizes, for example small sectors at beginning and end.
+ In this case gdb will have to have several memory_region objects each
+ one having uniform sector size.
+ This field is defined only of MEMORY_TYPE == TARGET_MEMORY_FLASH. */
+ unsigned flash_block_size;
+ } memory_region;
+
+DEF_VEC_O(memory_region);
+
+/* Casts both A and B to memory_region, compares they starting addresses
+ and returns value less than zero, equal to zero, or greater then zero
+ if A's starting address is less than B's starting address, equal to,
+ or greater then, respectively. This function is suitable for sorting
+ vector of memory_regions with the qsort function. */
+int compare_memory_region_starting_address (const void* a, const void *b);
+
+/* Parses XML memory map passed as argument and returns the memory
+ regions it describes. On any error, emits error message and
+ returns 0. Does not throw. Ownership of result is passed to the caller. */
+VEC(memory_region) *parse_memory_map (const char *memory_map);
+
+#endif
=== gdb/Makefile.in
==================================================================
--- gdb/Makefile.in (/mirrors/gdb) (revision 334)
+++ gdb/Makefile.in (/patches/memory_map/gdb) (revision 334)
@@ -535,7 +535,7 @@
language.c linespec.c \
m2-exp.y m2-lang.c m2-typeprint.c m2-valprint.c \
macrotab.c macroexp.c macrocmd.c macroscope.c main.c maint.c \
- mdebugread.c memattr.c mem-break.c minsyms.c mipsread.c \
+ mdebugread.c memattr.c mem-break.c minsyms.c mipsread.c memory-map.c \
nlmread.c \
objc-exp.y objc-lang.c \
objfiles.c osabi.c observer.c \
@@ -745,6 +745,7 @@
mips_mdebug_tdep_h = mips-mdebug-tdep.h
mipsnbsd_tdep_h = mipsnbsd-tdep.h
mips_tdep_h = mips-tdep.h
+memory_map_h = memory-map.h $(vec_h)
mn10300_tdep_h = mn10300-tdep.h
monitor_h = monitor.h
nbsd_tdep_h = nbsd-tdep.h
@@ -794,7 +795,8 @@
stack_h = stack.h
symfile_h = symfile.h
symtab_h = symtab.h
-target_h = target.h $(bfd_h) $(symtab_h) $(dcache_h) $(memattr_h)
+target_h = target.h $(bfd_h) $(symtab_h) $(dcache_h) $(memattr_h) $(vec_h) \
+ $(memory_map_h)
terminal_h = terminal.h
top_h = top.h
tracepoint_h = tracepoint.h
@@ -953,7 +955,7 @@
trad-frame.o \
tramp-frame.o \
solib.o solib-null.o \
- prologue-value.o
+ prologue-value.o vec.o memory-map.o
TSOBS = inflow.o
@@ -2359,6 +2361,8 @@
$(floatformat_h)
mipsv4-nat.o: mipsv4-nat.c $(defs_h) $(inferior_h) $(gdbcore_h) $(target_h) \
$(regcache_h) $(gregset_h)
+memory-map.o: memory-map.c $(defs_h) $(memory_map_h) $(gdb_assert_h) \
+ $(exceptions_h) $(gdb_string_h)
mn10300-linux-tdep.o: mn10300-linux-tdep.c $(defs_h) $(gdbcore_h) \
$(gdb_string_h) $(regcache_h) $(mn10300_tdep_h) $(gdb_assert_h) \
$(bfd_h) $(elf_bfd_h) $(osabi_h) $(regset_h) $(solib_svr4_h) \
@@ -2487,7 +2491,7 @@
$(gdb_stabs_h) $(gdbthread_h) $(remote_h) $(regcache_h) $(value_h) \
$(gdb_assert_h) $(event_loop_h) $(event_top_h) $(inf_loop_h) \
$(serial_h) $(gdbcore_h) $(remote_fileio_h) $(solib_h) $(observer_h) \
- $(cli_decode_h) $(cli_setshow_h)
+ $(cli_decode_h) $(cli_setshow_h) $(memory_map_h)
remote-e7000.o: remote-e7000.c $(defs_h) $(gdbcore_h) $(gdbarch_h) \
$(inferior_h) $(target_h) $(value_h) $(command_h) $(gdb_string_h) \
$(exceptions_h) $(gdbcmd_h) $(serial_h) $(remote_utils_h) \
=== gdb/exceptions.h
==================================================================
--- gdb/exceptions.h (/mirrors/gdb) (revision 334)
+++ gdb/exceptions.h (/patches/memory_map/gdb) (revision 334)
@@ -71,6 +71,9 @@
more detail. */
TLS_GENERIC_ERROR,
+ /* Problem parsing XML memory map. */
+ XML_MEMORY_MAP_ERROR,
+
/* Add more errors here. */
NR_ERRORS
};