[PATCH] Add OSE operating system support [3/5] remote relocation support

Hui Zhu hui_zhu@mentor.com
Tue Mar 5 10:01:00 GMT 2013


Hi,

This patch add relocation support to remote target.
If target support qXfer:load-map:read, it use this packet to request a list of segment or section load addresses of the main executable.
If target doesn't support it, use qOffsets that support in before request section offsets.

Thanks,
Hui

2013-03-05  Luis Machado  <lgustavo@codesourcery.com>

	* corelow.c (Makefile.in): Add load-map.dtd.
	* features/load-map.dtd: New.
	* remote.c (get_offsets): Removed.
	(PACKET_qXfer_load_map, load_map_start_segment,
	load_map_start_section, load_map_start, load_map_end,
	free_load_map, free_current_contents_load_map,
	segment_attributes, section_attributes, load_map_children,
	load_map_attributes, load_map_elements, parse_load_map,
	remote_relocate_using_qXfer_load_map,
	remote_relocate_using_qOffsets, remote_relocate): New.
	(remote_start_remote): Call remote_relocate.
	(remote_pr): Add qXfer:load-map:read.
	(extended_remote_attach_1): Call remote_relocate.
	(remote_xfer_partial): Handle TARGET_OBJECT_LOAD_MAP.
	(_initialize_remote): Add load-map command.
-------------- next part --------------
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -496,8 +496,9 @@ RUNTESTFLAGS=
 # XML files to build in to GDB.
 XMLFILES = $(srcdir)/features/gdb-target.dtd $(srcdir)/features/xinclude.dtd \
 	$(srcdir)/features/library-list.dtd \
-	$(srcdir)/features/library-list-svr4.dtd $(srcdir)/features/osdata.dtd \
-	$(srcdir)/features/threads.dtd $(srcdir)/features/traceframe-info.dtd
+	$(srcdir)/features/library-list-svr4.dtd $(srcdir)/features/load-map.dtd \
+	$(srcdir)/features/osdata.dtd $(srcdir)/features/threads.dtd \
+	$(srcdir)/features/traceframe-info.dtd
 
 # This is ser-unix.o for any system which supports a v7/BSD/SYSV/POSIX
 # interface to the serial port.  Hopefully if get ported to OS/2, VMS,
--- /dev/null
+++ b/gdb/features/load-map.dtd
@@ -0,0 +1,15 @@
+<!-- Copyright (C) 2010 Free Software Foundation, Inc.
+
+     Copying and distribution of this file, with or without modification,
+     are permitted in any medium without royalty provided the copyright
+     notice and this notice are preserved.  -->
+
+<!-- load-map: Root element with versioning -->
+<!ELEMENT load-map  (segment*, section*)>
+<!ATTLIST load-map  version CDATA   #FIXED  "1.0">
+
+<!ELEMENT segment       EMPTY>
+<!ATTLIST segment       address CDATA   #REQUIRED>
+
+<!ELEMENT section       EMPTY>
+<!ATTLIST section       address CDATA   #REQUIRED>
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -143,8 +143,6 @@ static void interrupt_query (void);
 static void set_general_thread (struct ptid ptid);
 static void set_continue_thread (struct ptid ptid);
 
-static void get_offsets (void);
-
 static void skip_frame (void);
 
 static long read_frame (char **buf_p, long *sizeof_buf);
@@ -1258,6 +1256,7 @@ enum {
   PACKET_qXfer_statictrace_read,
   PACKET_qXfer_traceframe_info,
   PACKET_qXfer_uib,
+  PACKET_qXfer_load_map,
   PACKET_qGetTIBAddr,
   PACKET_qGetTLSAddr,
   PACKET_qSupported,
@@ -3031,10 +3030,203 @@ remote_close (int quitting)
   remote_notif_unregister_async_event_handler ();
 }
 
-/* Query the remote side for the text, data and bss offsets.  */
+#if defined(HAVE_LIBEXPAT)
+
+/* Handle the start of a <segment> element.  */
 
 static void
-get_offsets (void)
+load_map_start_segment (struct gdb_xml_parser *parser,
+			const struct gdb_xml_element *element,
+			void *user_data, VEC(gdb_xml_value_s) *attributes)
+{
+  struct load_map_info *info = user_data;
+  ULONGEST *address_p = xml_find_attribute (attributes, "address")->value;
+  CORE_ADDR address = (CORE_ADDR) *address_p;
+
+  if (info->section_bases != NULL)
+    gdb_xml_error (parser,
+		   _("Library list with both segments and sections"));
+
+  VEC_safe_push (CORE_ADDR, info->section_bases, address);
+}
+
+/* Handle the start of a <section> element.  */
+
+static void
+load_map_start_section (struct gdb_xml_parser *parser,
+			const struct gdb_xml_element *element,
+			void *user_data, VEC(gdb_xml_value_s) *attributes)
+{
+  struct load_map_info *info = user_data;
+  ULONGEST *address_p = xml_find_attribute (attributes, "address")->value;
+  CORE_ADDR address = (CORE_ADDR) *address_p;
+
+  if (info->segment_bases != NULL)
+    gdb_xml_error (parser,
+		   _("Offsets with both segments and sections"));
+
+  VEC_safe_push (CORE_ADDR, info->segment_bases, address);
+}
+
+/* Handle the start of a <load-map> element.  */
+
+static void
+load_map_start (struct gdb_xml_parser *parser,
+		const struct gdb_xml_element *element,
+		void *user_data, VEC(gdb_xml_value_s) *attributes)
+{
+  char *version = xml_find_attribute (attributes, "version")->value;
+
+  if (strcmp (version, "1.0") != 0)
+    gdb_xml_error (parser,
+		   _("Offsets list has unsupported version \"%s\""),
+		   version);
+}
+
+/* Handle the end of a <load-map> element.  */
+
+static void
+load_map_end (struct gdb_xml_parser *parser,
+	      const struct gdb_xml_element *element,
+	      void *user_data, const char *body_text)
+{
+  struct load_map_info *load_map_info = user_data;
+
+  if (load_map_info->segment_bases == NULL
+      && load_map_info->section_bases == NULL)
+    gdb_xml_error (parser,
+		   _("No segment or section bases defined"));
+}
+
+/* Discard the constructed load map.  */
+
+static void
+free_load_map (void *p)
+{
+  struct load_map_info *info = p;
+
+  VEC_free (CORE_ADDR, info->segment_bases);
+  VEC_free (CORE_ADDR, info->section_bases);
+  xfree (info);
+}
+
+static void
+free_current_contents_load_map (void *p)
+{
+  struct load_map_info **info = p;
+
+  free_load_map (*info);
+  *info = NULL;
+}
+
+/* The allowed elements and attributes for an XML load map.  The root
+   element is a <load-map>.  */
+
+static const struct gdb_xml_attribute segment_attributes[] = {
+  { "address", GDB_XML_AF_NONE, gdb_xml_parse_attr_ulongest, NULL },
+  { NULL, GDB_XML_AF_NONE, NULL, NULL }
+};
+
+static const struct gdb_xml_attribute section_attributes[] = {
+  { "address", GDB_XML_AF_NONE, gdb_xml_parse_attr_ulongest, NULL },
+  { NULL, GDB_XML_AF_NONE, NULL, NULL }
+};
+
+static const struct gdb_xml_element load_map_children[] = {
+  { "segment", segment_attributes, NULL,
+    GDB_XML_EF_REPEATABLE | GDB_XML_EF_OPTIONAL,
+    load_map_start_segment, NULL },
+  { "section", section_attributes, NULL,
+    GDB_XML_EF_REPEATABLE | GDB_XML_EF_OPTIONAL,
+    load_map_start_section, NULL },
+  { NULL, NULL, NULL, GDB_XML_EF_NONE, NULL, NULL }
+};
+
+static const struct gdb_xml_attribute load_map_attributes[] = {
+  { "version", GDB_XML_AF_NONE, NULL, NULL },
+  { NULL, GDB_XML_AF_NONE, NULL, NULL }
+};
+
+static const struct gdb_xml_element load_map_elements[] = {
+  { "load-map", load_map_attributes, load_map_children,
+    GDB_XML_EF_NONE, load_map_start, load_map_end },
+  { NULL, NULL, NULL, GDB_XML_EF_NONE, NULL, NULL }
+};
+
+static struct load_map_info *
+parse_load_map (const char *load_map)
+{
+  struct load_map_info *result = XCNEW (struct load_map_info);
+  struct cleanup *back_to = make_cleanup (free_current_contents_load_map,
+					  &result);
+
+  if (gdb_xml_parse_quick (_("load map"), "load-map.dtd",
+			   load_map_elements, load_map, result) == 0)
+    {
+      /* Parsed successfully, keep the result.  */
+      discard_cleanups (back_to);
+      return result;
+    }
+
+  do_cleanups (back_to);
+  return NULL;
+}
+
+#endif
+
+/* Relocate the main symbol file and executable using the load
+   addresses as reported by a qXfer:load-map:read query.  Returns true
+   if the target supported the query, false otherwise.  We'll still
+   try qOffsets in the latter case.  */
+
+static int
+remote_relocate_using_qXfer_load_map (void)
+{
+#if defined(HAVE_LIBEXPAT)
+  if (remote_protocol_packets[PACKET_qXfer_load_map].support == PACKET_ENABLE)
+    {
+      struct section_offsets *offs;
+      const char *load_map_document;
+      struct load_map_info *info;
+      struct bfd *abfd;
+      const char *filename;
+      struct cleanup *old_chain;
+
+      /* Fetch the offset list.  */
+
+      load_map_document = target_read_stralloc (&current_target,
+						TARGET_OBJECT_LOAD_MAP,
+						NULL);
+      if (load_map_document == NULL)
+	return 0;
+
+      old_chain = make_cleanup (xfree, (void *) load_map_document);
+
+      /* Parse the list.  */
+      info = parse_load_map (load_map_document);
+      if (info == NULL)
+	{
+	  do_cleanups (old_chain);
+	  return 0;
+	}
+
+      make_cleanup (free_load_map, info);
+
+      relocate_with_load_map (info);
+
+      do_cleanups (old_chain);
+      return 1;
+    }
+#endif
+
+  return 0;
+}
+
+/* Query the remote side for the text, data and bss section offsets,
+   or text and data segment load bases.  */
+
+static void
+remote_relocate_using_qOffsets (void)
 {
   struct remote_state *rs = get_remote_state ();
   char *buf;
@@ -3044,9 +3236,6 @@ get_offsets (void)
   struct section_offsets *offs;
   struct symfile_segment_data *data;
 
-  if (symfile_objfile == NULL)
-    return;
-
   putpkt ("qOffsets");
   getpkt (&rs->buf, &rs->buf_size, 0);
   buf = rs->buf;
@@ -3190,6 +3379,17 @@ get_offsets (void)
   objfile_relocate (symfile_objfile, offs);
 }
 
+static void
+remote_relocate (void)
+{
+  if (symfile_objfile == NULL)
+    return;
+
+  if (remote_relocate_using_qXfer_load_map ())
+    return;
+  remote_relocate_using_qOffsets ();
+}
+
 /* Callback for iterate_over_threads.  Set the STOP_REQUESTED flags in
    threads we know are stopped already.  This is used during the
    initial remote connection in non-stop mode --- threads that are
@@ -3468,7 +3668,9 @@ remote_start_remote (int from_tty, struc
 	 manipulation.  */
       init_wait_for_inferior ();
 
-      get_offsets ();		/* Get text, data & bss offsets.  */
+      /* Get section/segment load offsets/addresses from the
+	 target.  */
+      remote_relocate ();
 
       /* If we could not find a description using qXfer, and we know
 	 how to do it some other way, try again.  This is not
@@ -3542,7 +3744,9 @@ remote_start_remote (int from_tty, struc
       if (ptid_equal (inferior_ptid, minus_one_ptid))
 	error (_("remote didn't report the current thread in non-stop mode"));
 
-      get_offsets ();		/* Get text, data & bss offsets.  */
+      /* Get section/segment load offsets/addresses from the
+	 target.  */
+      remote_relocate ();
 
       /* In non-stop mode, any cached wait status will be stored in
 	 the stop reply queue.  */
@@ -3950,6 +4154,8 @@ static struct protocol_feature remote_pr
     PACKET_qXfer_threads },
   { "qXfer:traceframe-info:read", PACKET_DISABLE, remote_supported_packet,
     PACKET_qXfer_traceframe_info },
+  { "qXfer:load-map:read", PACKET_DISABLE, remote_supported_packet,
+    PACKET_qXfer_load_map },
   { "QPassSignals", PACKET_DISABLE, remote_supported_packet,
     PACKET_QPassSignals },
   { "QProgramSignals", PACKET_DISABLE, remote_supported_packet,
@@ -4519,6 +4725,9 @@ extended_remote_attach_1 (struct target_
      this before anything involving memory or registers.  */
   target_find_description ();
 
+  /* Get updated relocation offsets.  */
+  remote_relocate ();
+
   if (!non_stop)
     {
       /* Use the previously fetched status.  */
@@ -7950,7 +8159,7 @@ extended_remote_create_inferior_1 (char
     {
       /* Clean up from the last time we ran, before we mark the target
 	 running again.  This will mark breakpoints uninserted, and
-	 get_offsets may insert breakpoints.  */
+	 remote_relocate may insert breakpoints.  */
       init_thread_list ();
       init_wait_for_inferior ();
     }
@@ -7959,8 +8168,8 @@ extended_remote_create_inferior_1 (char
   stop_reply = run_worked ? rs->buf : NULL;
   add_current_inferior_and_thread (stop_reply);
 
-  /* Get updated offsets, if the stub uses qOffsets.  */
-  get_offsets ();
+  /* Get section/segment load offsets/addresses from the target.  */
+  remote_relocate ();
 }
 
 static void
@@ -8796,6 +9005,10 @@ remote_xfer_partial (struct target_ops *
       return remote_read_qxfer (ops, "uib", annex, readbuf, offset, len,
 				&remote_protocol_packets[PACKET_qXfer_uib]);
 
+    case TARGET_OBJECT_LOAD_MAP:
+      gdb_assert (annex == NULL);
+      return remote_read_qxfer (ops, "load-map", annex, readbuf, offset, len,
+				&remote_protocol_packets[PACKET_qXfer_load_map]);
     default:
       return -1;
     }
@@ -11663,6 +11876,9 @@ Show the maximum size of the address (in
   add_packet_config_cmd (&remote_protocol_packets[PACKET_qXfer_uib],
 			 "qXfer:uib:read", "unwind-info-block", 0);
 
+  add_packet_config_cmd (&remote_protocol_packets[PACKET_qXfer_load_map],
+			 "qXfer:load-map:read", "load-map", 0);
+
   add_packet_config_cmd (&remote_protocol_packets[PACKET_qGetTLSAddr],
 			 "qGetTLSAddr", "get-thread-local-storage-address",
 			 0);


More information about the Binutils mailing list