This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: Flash support part 1: memory maps


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 (&current_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
 };

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]