This is the mail archive of the
gdb@sourceware.org
mailing list for the GDB project.
Re: GDB solib interface
On Mon, Dec 04, 2006 at 05:28:47PM -0500, Daniel Jacobowitz wrote:
> On Mon, Dec 04, 2006 at 03:12:27PM -0700, Smith, Stephen (SWCOE) wrote:
> >
> > I'm sorry - way back when Kevin asked that I investigate this. So now I
> > am.
> >
> > Anyway - Pretend that my "custom" GDB remote.c has been told that a
> > library has been loaded - what would I need to write to use the solib
> > interface? Another way of asking the question would be, what would I
> > need to add to my remote interface file (remote.c) to have it load the
> > symbols.
> >
> > I am not looking for a command, per se, just trying to figure out what
> > functions/structures etc I need to write to have my "custom" GDB load
> > the libraries symbols.
>
> Aha. OK, that's different.
>
> I wrote some code for this purpose, a few months ago, which I meant to
> submit. That was for DLL targets. I haven't had time yet. I'm afraid
> it's not real easy to untangle from the rest of that project now :-(
Here you go. I haven't tested this patch on its own at all, so if it
breaks, you get to keep both pieces. Add solib-target.o to TDEPFILES
for your target to enable it.
It works by two mechanisms. You can send "qfDllInfo" to get the entire
list from a remote target, and the remote target can report load /
unload events as special 'T' stop packets. It should be fairly
apparent from the code.
Some draft docs I wrote at the time:
`qfDllInfo'
`qsDllInfo'
Obtain a list of currently loaded DLLs from the target. Like
`qfThreadInfo', this request works iteratively. The `qfDllInfo'
packet is issued first to start at the beginning of the DLL list,
and the `qsDllInfo' packet is used to fetch additional entries.
Reply:
`m' Name=HEXSTR,TextSeg=ADDR,DataSeg=ADDR
Returns the name (as a hexadecimal-encoded sequence of ASCII
characters), text load address, and data load address for this DLL.
Other Name=Value pairs may be added in the future for particular
targets.
`m' Name=HEXSTR,TextSeg=ADDR,DataSeg=ADDR;Name=HEXSTR,TextSeg=ADDR,DataSeg=ADDR...
Multiple DLL entries may be included in the same packet; a semicolon
marks the start of a new DLL description. A single DLL
will never be split across multiple packets.
`l'
Marks the end of a list of DLLs.
[Editorial note: maybe use `ml' instead? Then we can use
`mName=FOO,TextSeg=ADDR,DataSeg=ADDR;l' and save a round trip. This is not quite
parallel to qfThreadInfo but that should be ok.]
[Editorial note: No support is provided for DLLs with extremely long names
that do not fit in a packet. A solution for this can be added at a later
date if necessary.]
If any stopped threads had DLL events not yet reported to GDB, either the
effects of those events should not be included in the result of the query,
or the queued DLL events should be discarded before they are reported to
GDB.
[Editorial note: You wrote that every dlopen triggers an event even if the
DLL was already loaded. Should the stub drop the event in that case?
Should it report it anyway and have duplicates handled on the GDB side?
That would let the long-lost "catch load <libname>" command work again.
If so, then the above paragraph must be deleted and some words about how
GDB should ignore apparent duplicates added.]
Reporting DLL events
--------------------
The `T' stop packet response is extended to take three additional
N:R pairs. When any of these are encountered, the stopped thread
is assumed to be at a DLL event. The signal should be SIGTRAP.
There may be multiple load and unload events in the stop packet.
`load:Name=HEXSTR,TextSeg=ADDR,DataSeg=ADDR[,nop]'
A new DLL has been loaded; it is described in the stop packet.
If "nop" is specified, this DLL was already loaded, e.g. by
an earlier call to dlopen.
`unload:IDENTIFIER=VALUE[,nop]'
A DLL has been unloaded. A single identifier is provided to
uniquely identify which DLL has been unloaded. Depending
on the target, this may be the text or data address; the name
can be used, but may not be unambiguous.
If "nop" is specified, this DLL was not unloaded, e.g. because
another thread still had a handle to it.
`dll:dll'
Multiple DLL events have occured. GDB should query the target for the
current state of DLLs.
--
Daniel Jacobowitz
CodeSourcery
Index: Makefile.in
===================================================================
RCS file: /cvs/src/src/gdb/Makefile.in,v
retrieving revision 1.856
diff -u -p -r1.856 Makefile.in
--- Makefile.in 28 Nov 2006 22:14:31 -0000 1.856
+++ Makefile.in 8 Dec 2006 21:09:03 -0000
@@ -2516,7 +2516,8 @@ remote.o: remote.c $(defs_h) $(gdb_strin
$(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) $(memory_map_h) $(target_descriptions_h)
+ $(cli_decode_h) $(cli_setshow_h) $(memory_map_h) $(target_descriptions_h) \
+ $(solist_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) \
@@ -2650,6 +2651,8 @@ solib-svr4.o: solib-svr4.c $(defs_h) $(e
$(gdbcore_h) $(target_h) $(inferior_h) $(gdb_assert_h) \
$(solist_h) $(solib_h) $(solib_svr4_h) $(bfd_target_h) $(elf_bfd_h) \
$(exec_h)
+solib-target.o: solib-target.c $(defs_h) $(solist_h) $(symtab_h) $(symfile_h) \
+ $(target_h) $(gdb_string_h)
sol-thread.o: sol-thread.c $(defs_h) $(gdbthread_h) $(target_h) \
$(inferior_h) $(gdb_stat_h) $(gdbcmd_h) $(gdbcore_h) $(regcache_h) \
$(solib_h) $(symfile_h) $(gdb_string_h) $(gregset_h)
Index: infrun.c
===================================================================
RCS file: /cvs/src/src/gdb/infrun.c,v
retrieving revision 1.216
diff -u -p -r1.216 infrun.c
--- infrun.c 18 Oct 2006 16:56:13 -0000 1.216
+++ infrun.c 8 Dec 2006 21:09:04 -0000
@@ -884,6 +884,8 @@ init_wait_for_inferior (void)
clear_proceed_status ();
stepping_past_singlestep_breakpoint = 0;
+
+ target_last_wait_ptid = minus_one_ptid;
}
/* This enum encodes possible reasons for doing a target_wait, so that
@@ -1262,6 +1264,9 @@ handle_inferior_event (struct execution_
target_last_wait_ptid = ecs->ptid;
target_last_waitstatus = *ecs->wp;
+ /* Always clear state belonging to the previous time we stopped. */
+ stop_stack_dummy = 0;
+
adjust_pc_after_break (ecs);
switch (ecs->infwait_state)
@@ -1322,13 +1327,16 @@ handle_inferior_event (struct execution_
/* Ignore gracefully during startup of the inferior, as it
might be the shell which has just loaded some objects,
otherwise add the symbols for the newly loaded objects. */
-#ifdef SOLIB_ADD
if (stop_soon == NO_STOP_QUIETLY)
{
+ int breakpoints_were_inserted;
+
/* Remove breakpoints, SOLIB_ADD might adjust
breakpoint addresses via breakpoint_re_set. */
+ breakpoints_were_inserted = breakpoints_inserted;
if (breakpoints_inserted)
remove_breakpoints ();
+ breakpoints_inserted = 0;
/* Check for any newly added shared libraries if we're
supposed to be adding them automatically. Switch
@@ -1350,17 +1358,52 @@ handle_inferior_event (struct execution_
exec/process stratum, instead relying on the target stack
to propagate relevant changes (stop, section table
changed, ...) up to other layers. */
+#ifdef SOLIB_ADD
SOLIB_ADD (NULL, 0, ¤t_target, auto_solib_add);
+#else
+ solib_add (NULL, 0, ¤t_target, auto_solib_add);
+#endif
target_terminal_inferior ();
+ /* Try to reenable shared library breakpoints, additional
+ code segments in shared libraries might be mapped in now. */
+ re_enable_breakpoints_in_shlibs ();
+
+ /* If requested, stop when the dynamic linker notifies
+ gdb of events. This allows the user to get control
+ and place breakpoints in initializer routines for
+ dynamically loaded objects (among other things). */
+ if (stop_on_solib_events)
+ {
+ stop_stepping (ecs);
+ return;
+ }
+
+ /* NOTE drow/2006-03-14: This might be a good place to check
+ for "catch load". */
+
/* Reinsert breakpoints and continue. */
- if (breakpoints_inserted)
- insert_breakpoints ();
+ if (breakpoints_were_inserted)
+ {
+ insert_breakpoints ();
+ breakpoints_inserted = 1;
+ }
}
-#endif
- resume (0, TARGET_SIGNAL_0);
- prepare_to_wait (ecs);
- return;
+
+ /* NOTE drow/2006-03-28: For the reason described before the
+ previous if statement, GDB used to automatically resume
+ here. But that's only true if a shell is running; if
+ we've just attached to a process, then that's a whole
+ different case - it might have been stopped at a load
+ event. */
+ if (inferior_ignoring_startup_exec_events || stop_soon == NO_STOP_QUIETLY)
+ {
+ resume (0, TARGET_SIGNAL_0);
+ prepare_to_wait (ecs);
+ return;
+ }
+ else
+ break;
case TARGET_WAITKIND_SPURIOUS:
if (debug_infrun)
@@ -1779,7 +1822,6 @@ handle_inferior_event (struct execution_
ecs->another_trap = 0;
bpstat_clear (&stop_bpstat);
stop_step = 0;
- stop_stack_dummy = 0;
stop_print_frame = 1;
ecs->random_signal = 0;
stopped_by_random_signal = 0;
Index: remote.c
===================================================================
RCS file: /cvs/src/src/gdb/remote.c,v
retrieving revision 1.241
diff -u -p -r1.241 remote.c
--- remote.c 28 Nov 2006 22:14:31 -0000 1.241
+++ remote.c 8 Dec 2006 21:09:04 -0000
@@ -43,6 +43,7 @@
#include "gdb_assert.h"
#include "observer.h"
#include "solib.h"
+#include "solist.h"
#include "cli/cli-decode.h"
#include "cli/cli-setshow.h"
#include "target-descriptions.h"
@@ -897,6 +898,7 @@ enum {
PACKET_qGetTLSAddr,
PACKET_qSupported,
PACKET_QPassSignals,
+ PACKET_qfDllInfo,
PACKET_MAX
};
@@ -2076,6 +2078,152 @@ get_offsets (void)
objfile_relocate (symfile_objfile, offs);
}
+/* Parse a load or unload message for a DLL. Loads are required to
+ have all fields, unloads must have at least one. P is not
+ necessarily NUL terminated, but it is always either NUL or semicolon
+ terminated (i.e. *P_END is either NUL or a semicolon) and the containing
+ string is NUL terminated. */
+
+int
+parse_load_response (const char *p, const char *p_end, int is_load)
+{
+ const char *name_start;
+ char *name;
+ CORE_ADDR text_addr, data_addr;
+ int i;
+
+ name = NULL;
+ text_addr = ~(CORE_ADDR) 0;
+ data_addr = ~(CORE_ADDR) 0;
+
+ if (p < p_end && strncmp (p, "Name=", 5) == 0)
+ {
+ p += 5;
+
+ name_start = p;
+ while (p < p_end && *p != ',')
+ p++;
+
+ if ((p - name_start) % 2 != 0)
+ return -1;
+
+ name = alloca ((p - name_start) / 2 + 1);
+ i = hex2bin (name_start, name, (p - name_start) / 2);
+ name[i] = '\0';
+
+ if (p < p_end)
+ p++;
+ }
+ else if (is_load)
+ return -1;
+
+ if (p < p_end && strncmp (p, "TextSeg=", 8) == 0)
+ {
+ p += 8;
+
+ text_addr = 0;
+ while (p < p_end && *p != ',')
+ text_addr = (text_addr << 4) + fromhex (*p++);
+
+ if (p < p_end)
+ p++;
+ }
+ else if (is_load)
+ return -1;
+
+ if (p < p_end && strncmp (p, "DataSeg=", 8) == 0)
+ {
+ p += 8;
+
+ data_addr = 0;
+ while (p < p_end && *p != ',')
+ data_addr = (data_addr << 4) + fromhex (*p++);
+
+ if (p < p_end)
+ p++;
+ }
+ else if (is_load)
+ return -1;
+
+ if (is_load)
+ current_target_so_ops->add_one_solib (name, text_addr, data_addr);
+ else
+ {
+ if (text_addr == ~(CORE_ADDR) 0
+ && data_addr == ~(CORE_ADDR) 0
+ && name == NULL)
+ return -1;
+
+ current_target_so_ops->remove_one_solib (name, text_addr, data_addr);
+ }
+
+ return 0;
+}
+
+/* Query the remote side for loaded solibs. */
+
+static void
+remote_get_shared_libraries (struct target_ops *ops)
+{
+ struct remote_state *rs = get_remote_state ();
+
+ /* If this target doesn't support remote DLLs, nothing to do. */
+ if (current_target_so_ops->add_one_solib == NULL)
+ return;
+
+ /* If qfDllInfo is not available, nothing to do. */
+ if (remote_protocol_packets[PACKET_qfDllInfo].support == PACKET_DISABLE)
+ return;
+
+ putpkt ("qfDllInfo");
+ getpkt (&rs->buf, &rs->buf_size, 0);
+
+ if (packet_ok (rs->buf, &remote_protocol_packets[PACKET_qfDllInfo]) == PACKET_ERROR)
+ {
+ warning (_("Remote failure reply: %s"), rs->buf);
+ return;
+ }
+ else if (remote_protocol_packets[PACKET_qfDllInfo].support == PACKET_DISABLE)
+ /* It wasn't disabled before, but it is now. */
+ return;
+
+ while (rs->buf[0] == 'm')
+ {
+ char *p = rs->buf + 1;
+
+ while (1)
+ {
+ char *p_end = p;
+
+ while (*p_end && *p_end != ';')
+ p_end++;
+
+ if (parse_load_response (p, p_end, 1) != 0)
+ {
+ warning (_("Malformed response to DLL query, %s"), rs->buf);
+ return;
+ }
+
+ if (*p_end == ';')
+ p = p_end + 1;
+ else
+ break;
+ }
+
+ putpkt ("qsDllInfo");
+ getpkt (&rs->buf, &rs->buf_size, 0);
+ }
+
+ if (strcmp (rs->buf, "l") != 0)
+ {
+ warning (_("Malformed response to DLL query, %s"), rs->buf);
+ return;
+ }
+
+ /* We don't need to call solib_add here, because we're being called from
+ ->current_sos (). */
+}
+
/* Stub for catch_exception. */
static void
@@ -3093,6 +3241,7 @@ remote_wait (ptid_t ptid, struct target_
struct remote_arch_state *rsa = get_remote_arch_state ();
ULONGEST thread_num = -1;
ULONGEST addr;
+ int solibs_changed = 0;
status->kind = TARGET_WAITKIND_EXITED;
status->value.integer = 0;
@@ -3178,6 +3327,60 @@ Packet: '%s'\n"),
p = unpack_varlen_hex (++p1, &addr);
remote_watch_data_address = (CORE_ADDR)addr;
}
+ else if (strncmp (p, "load", p1 - p) == 0)
+ {
+ p1++;
+ p_temp = p1;
+ while (*p_temp && *p_temp != ';')
+ p_temp++;
+
+ if (p_temp - p1 > 4
+ && strncmp (p_temp - 4, ",nop", 4) == 0)
+ {
+ /* For now, ignore no-op unload events. Later,
+ maybe report them? */
+ }
+ else
+ {
+ parse_load_response (p1, p_temp, 1);
+
+ solibs_changed = 1;
+ }
+
+ p = p_temp;
+ }
+ else if (strncmp (p, "unload", p1 - p) == 0)
+ {
+ p1++;
+ p_temp = p1;
+ while (*p_temp && *p_temp != ';')
+ p_temp++;
+
+ if (p_temp - p1 > 4
+ && strncmp (p_temp - 4, ",nop", 4) == 0)
+ {
+ /* For now, ignore no-op unload events. Later,
+ maybe report them? */
+ }
+ else
+ {
+ parse_load_response (p1, p_temp, 0);
+
+ solibs_changed = 1;
+ }
+
+ p = p_temp;
+ }
+ else if (strncmp (p, "dll", p1 - p) == 0)
+ {
+ p1++;
+ p_temp = p1;
+ while (*p_temp && *p_temp != ';')
+ p_temp++;
+
+ solibs_changed = -1;
+ p = p_temp;
+ }
else
{
/* Silently skip unknown optional info. */
@@ -3269,6 +3472,12 @@ Packet: '%s'\n"),
}
}
got_status:
+ if (solibs_changed == -1)
+ remote_get_shared_libraries (NULL);
+
+ if (solibs_changed != 0)
+ status->kind = TARGET_WAITKIND_LOADED;
+
if (thread_num != -1)
{
return pid_to_ptid (thread_num);
@@ -6203,6 +6412,7 @@ Specify the serial device it is connecte
remote_ops.to_flash_erase = remote_flash_erase;
remote_ops.to_flash_done = remote_flash_done;
remote_ops.to_read_description = remote_read_description;
+ remote_ops.to_get_shared_libraries = remote_get_shared_libraries;
}
/* Set up the extended remote vector by making a copy of the standard
@@ -6335,7 +6545,8 @@ Specify the serial device it is connecte
remote_async_ops.to_memory_map = remote_memory_map;
remote_async_ops.to_flash_erase = remote_flash_erase;
remote_async_ops.to_flash_done = remote_flash_done;
- remote_ops.to_read_description = remote_read_description;
+ remote_async_ops.to_read_description = remote_read_description;
+ remote_async_ops.to_get_shared_libraries = remote_get_shared_libraries;
}
/* Set up the async extended remote vector by making a copy of the standard
@@ -6601,6 +6812,9 @@ Show the maximum size of the address (in
add_packet_config_cmd (&remote_protocol_packets[PACKET_qSupported],
"qSupported", "supported-packets", 0);
+ add_packet_config_cmd (&remote_protocol_packets[PACKET_qfDllInfo],
+ "qfDllInfo", "dll-info", 0);
+
/* Keep the old ``set remote Z-packet ...'' working. Each individual
Z sub-packet has its own set and show commands, but users may
have sets to this variable in their .gdbinit files (or in their
Index: solib-target.c
===================================================================
RCS file: solib-target.c
diff -N solib-target.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ solib-target.c 8 Dec 2006 21:09:04 -0000
@@ -0,0 +1,269 @@
+/* Definitions for targets which report shared library events.
+
+ 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 "solist.h"
+#include "symtab.h"
+#include "symfile.h"
+#include "target.h"
+
+#include "gdb_string.h"
+
+struct lm_info
+{
+ CORE_ADDR textSeg, dataSeg;
+};
+
+static struct so_list *solib_start;
+static int solibs_fetched;
+
+static struct so_list *
+solib_target_current_sos (void)
+{
+ struct so_list *sop;
+ struct so_list *start = NULL;
+ struct so_list *last = NULL;
+
+ /* If we have not asked the target for the list of shared libraries
+ yet, do it now. */
+ if (!solibs_fetched)
+ {
+ solibs_fetched = 1;
+ target_get_shared_libraries ();
+ }
+
+ for (sop = solib_start; sop; sop = sop->next)
+ {
+ struct so_list *new;
+
+ /* Duplicate the recorded solib. */
+ new = XZALLOC (struct so_list);
+ strcpy (new->so_name, sop->so_name);
+ strcpy (new->so_original_name, sop->so_original_name);
+ new->lm_info = XMALLOC (struct lm_info);
+ *new->lm_info = *sop->lm_info;
+
+ /* Add it to the list. */
+ if (!start)
+ last = start = new;
+ else
+ {
+ last->next = new;
+ last = new;
+ }
+ }
+
+ return start;
+}
+
+static void
+solib_target_special_symbol_handling (void)
+{
+ /* Nothing needed. */
+}
+
+static void
+solib_target_solib_create_inferior_hook (void)
+{
+ /* Nothing needed. */
+}
+
+static void
+solib_target_clear_solib (void)
+{
+ struct so_list *sop, *next;
+
+ for (sop = solib_start; sop; sop = next)
+ {
+ next = sop->next;
+
+ free_so (sop);
+ }
+
+ solib_start = NULL;
+ solibs_fetched = 0;
+}
+
+static void
+solib_target_free_so (struct so_list *so)
+{
+ xfree (so->lm_info);
+}
+
+static void
+solib_target_relocate_section_addresses (struct so_list *so,
+ struct section_table *sec)
+{
+ int flags = bfd_get_section_flags (sec->bfd, sec->the_bfd_section);
+ CORE_ADDR offset;
+
+ offset = symfile_section_offset_from_segment (sec->bfd, sec->the_bfd_section,
+ so->lm_info->textSeg,
+ so->lm_info->dataSeg);
+
+ sec->addr += offset;
+ sec->endaddr += offset;
+
+ /* If we haven't set these yet, do so now. If this fails, we may waste some
+ cycles uselessly retrying it, but that is rare and harmless. */
+ if (so->addr_low == 0 && so->addr_high == 0)
+ {
+ CORE_ADDR text_len, data_len;
+
+ symfile_find_segment_lengths (sec->bfd, &text_len, &data_len);
+
+ if (text_len)
+ {
+ so->addr_low = so->lm_info->textSeg;
+ so->addr_high = so->addr_low + text_len;
+ }
+ else if (data_len)
+ {
+ so->addr_low = so->lm_info->dataSeg;
+ so->addr_high = so->addr_low + data_len;
+ }
+ }
+}
+
+static int
+solib_target_open_symbol_file_object (void *from_ttyp)
+{
+ /* We can't locate the main symbol file based on the target's
+ knowledge; the user has to specify it. */
+ return 0;
+}
+
+static int
+solib_target_in_dynsym_resolve_code (CORE_ADDR pc)
+{
+ /* Assume there isn't target dynsym resolution code. DLL targets
+ generally have only import stubs (which GDB treats as "PLT entries"),
+ and no runtime binding code. */
+ return 0;
+}
+
+static void
+solib_target_add_one_solib (char *soname, CORE_ADDR textSeg,
+ CORE_ADDR dataSeg)
+{
+ struct so_list *new_solib, *so;
+
+ /* We should already have queried the target for shared libraries
+ before this point. If we haven't, we may have just connected;
+ we'll be querying shortly. */
+ if (!solibs_fetched)
+ return;
+
+ /* Check for duplicates already on the list. This can happen, for
+ instance, if we are stopped at a DLL load event when we first
+ connect to a remote target: the DLL will already be in the
+ queried list, but also be reported by the initial wait. */
+ for (so = solib_start; so; so = so->next)
+ if (strcmp (so->so_name, soname) == 0
+ && so->lm_info->textSeg == textSeg
+ && so->lm_info->dataSeg == dataSeg)
+ return;
+
+ new_solib = XZALLOC (struct so_list);
+ strncpy (new_solib->so_name, soname, SO_NAME_MAX_PATH_SIZE - 1);
+ new_solib->so_name[SO_NAME_MAX_PATH_SIZE - 1] = '\0';
+ strncpy (new_solib->so_original_name, soname, SO_NAME_MAX_PATH_SIZE - 1);
+ new_solib->so_original_name[SO_NAME_MAX_PATH_SIZE - 1] = '\0';
+
+ new_solib->lm_info = XZALLOC (struct lm_info);
+ new_solib->lm_info->textSeg = textSeg;
+ new_solib->lm_info->dataSeg = dataSeg;
+
+ if (solib_start == NULL)
+ solib_start = new_solib;
+ else
+ {
+ so = solib_start;
+ while (so->next)
+ so = so->next;
+ so->next = new_solib;
+ }
+
+ /* We do not trigger symbol reading here; the target will do it,
+ after all load events have been processed. */
+}
+
+static void
+solib_target_remove_one_solib (char *soname, CORE_ADDR textSeg,
+ CORE_ADDR dataSeg)
+{
+ struct so_list **slot, *removed;
+
+ /* We should already have queried the target for shared libraries
+ before this point. If we haven't, we may have just connected;
+ we'll be querying shortly. */
+ if (!solibs_fetched)
+ return;
+
+ for (slot = &solib_start; *slot != NULL; slot = &(*slot)->next)
+ {
+ if (textSeg != ~(CORE_ADDR) 0 && textSeg != (*slot)->lm_info->textSeg)
+ continue;
+ if (dataSeg != ~(CORE_ADDR) 0 && dataSeg != (*slot)->lm_info->dataSeg)
+ continue;
+ if (soname != NULL && strcmp (soname, (*slot)->so_name) != 0)
+ continue;
+ break;
+ }
+
+ if (*slot == NULL)
+ return;
+
+ removed = *slot;
+ *slot = removed->next;
+
+ free_so (removed);
+
+ /* We do not trigger symbol unloading here; the target will do it,
+ after all unload events have been processed. */
+}
+
+static struct target_so_ops solib_target_so_ops;
+
+extern initialize_file_ftype _initialize_solib_target; /* -Wmissing-prototypes */
+
+void
+_initialize_solib_target (void)
+{
+ solib_target_so_ops.relocate_section_addresses
+ = solib_target_relocate_section_addresses;
+ solib_target_so_ops.free_so = solib_target_free_so;
+ solib_target_so_ops.clear_solib = solib_target_clear_solib;
+ solib_target_so_ops.solib_create_inferior_hook
+ = solib_target_solib_create_inferior_hook;
+ solib_target_so_ops.special_symbol_handling
+ = solib_target_special_symbol_handling;
+ solib_target_so_ops.current_sos = solib_target_current_sos;
+ solib_target_so_ops.open_symbol_file_object
+ = solib_target_open_symbol_file_object;
+ solib_target_so_ops.in_dynsym_resolve_code
+ = solib_target_in_dynsym_resolve_code;
+ solib_target_so_ops.add_one_solib = solib_target_add_one_solib;
+ solib_target_so_ops.remove_one_solib = solib_target_remove_one_solib;
+
+ current_target_so_ops = &solib_target_so_ops;
+}
Index: solist.h
===================================================================
RCS file: /cvs/src/src/gdb/solist.h,v
retrieving revision 1.12
diff -u -p -r1.12 solist.h
--- solist.h 17 Dec 2005 22:34:02 -0000 1.12
+++ solist.h 8 Dec 2006 21:09:04 -0000
@@ -104,7 +104,11 @@ struct target_so_ops
Convenience function for remote debuggers finding host libs. */
int (*find_and_open_solib) (char *soname,
unsigned o_flags, char **temp_pathname);
-
+
+ void (*add_one_solib) (char *soname, CORE_ADDR textSeg,
+ CORE_ADDR dataSeg);
+ void (*remove_one_solib) (char *soname, CORE_ADDR textSeg,
+ CORE_ADDR dataSeg);
};
/* Free the memory associated with a (so_list *). */
Index: target.c
===================================================================
RCS file: /cvs/src/src/gdb/target.c,v
retrieving revision 1.131
diff -u -p -r1.131 target.c
--- target.c 5 Dec 2006 20:38:13 -0000 1.131
+++ target.c 8 Dec 2006 21:09:05 -0000
@@ -470,6 +470,7 @@ update_current_target (void)
/* Do not inherit to_memory_map. */
/* Do not inherit to_flash_erase. */
/* Do not inherit to_flash_done. */
+ /* Do not inherit to_get_shared_libraries. */
}
#undef INHERIT
@@ -1716,6 +1717,27 @@ target_read_description (struct target_o
}
/* Look through the list of possible targets for a target that can
+ fetch shared libraries. */
+
+void
+target_get_shared_libraries (void)
+{
+ struct target_ops *t;
+
+ for (t = current_target.beneath; t != NULL; t = t->beneath)
+ {
+ if (t->to_get_shared_libraries != NULL)
+ {
+ t->to_get_shared_libraries (t);
+ break;
+ }
+ }
+
+ if (targetdebug)
+ fprintf_unfiltered (gdb_stdlog, "target_get_shared_libraries ()\n");
+}
+
+/* Look through the list of possible targets for a target that can
execute a run or attach command without any other data. This is
used to locate the default process stratum.
Index: target.h
===================================================================
RCS file: /cvs/src/src/gdb/target.h,v
retrieving revision 1.92
diff -u -p -r1.92 target.h
--- target.h 28 Nov 2006 22:10:26 -0000 1.92
+++ target.h 8 Dec 2006 21:09:05 -0000
@@ -497,6 +497,9 @@ struct target_ops
was available. */
const struct target_desc *(*to_read_description) (struct target_ops *ops);
+ /* Refresh the list of shared libraries. */
+ void (*to_get_shared_libraries) (struct target_ops *ops);
+
int to_magic;
/* Need sub-structure for target machine related rather than comm related?
*/
@@ -1208,6 +1211,10 @@ extern const struct target_desc *target_
#define RESUME_EXECD_VFORKING_CHILD_TO_GET_PARENT_VFORK() (0)
#endif
+/* Refresh the list of shared libraries from the target. */
+
+extern void target_get_shared_libraries (void);
+
/* Routines for maintenance of the target structures...
add_target: Add a target to the list of all possible targets.