--- 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 @@ + + + + + + + + + + + --- 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 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
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 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 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 . */ + +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 (¤t_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);