[RFA 4/4] Improved linker-debugger interface
Gary Benson
gbenson@redhat.com
Fri Jul 13 09:42:00 GMT 2012
Gary Benson wrote:
> This patch builds on the probes-based runtime linker interface,
> adding incremental library list loading.
Again, a minor update to make the testcase use standard_output_file.
Thanks,
Gary
--
http://gbenson.net/
-------------- next part --------------
gdb/
2012-07-12 Gary Benson <gbenson@redhat.com>
* breakpoint.h (handle_solib_event): Moved function definition
to solib.h, and added a new parameter.
* breakpoint.c (handle_solib_event): Moved function to solib.c
and added a new parameter.
(bpstat_stop_status): Pass new argument to handle_solib_event.
* solib.h (breakpoint.h): New include.
(handle_solib_event): Moved function definition from breakpoint.h
and added a new parameter.
* solib.c (handle_solib_event): Moved function from breakpoint.c
and added a new parameter.
* infrun.c (handle_inferior_event): Pass new argument to
handle_solib_event.
* solist.h (breakpoint.h): New include.
(target_so_ops): New field "handle_solib_event".
* solib-svr4.c (svr4_free_library_list): New forward declaration.
(probe_action): New enum.
(probe_info): New field "action".
(svr4_info): New field "solib_cache".
(free_solib_cache): New function.
(svr4_pspace_data_cleanup): Call the above.
(svr4_copy_library_list): New function.
(svr4_read_so_list): New parameter "prev_lm".
Changed return type from void to int.
Return nonzero on success, zero on error.
(svr4_current_sos): Return cached list if available.
Add new argument to calls to svr4_read_so_list.
(solib_event_probe_action): New function.
(solib_cache_update_full): Likewise.
(solib_cache_update_incremental): Likewise.
(svr4_handle_solib_event): Likewise.
(svr4_solib_create_inferior_hook): Free any cached solibs.
(_initialize_svr4_solib): Initialise svr4_so_ops.handle_solib_event.
gdb/testsuite
2012-07-12 Gary Benson <gbenson@redhat.com>
* gdb.base/info-shared.exp: New file.
* gdb.base/info-shared.c: Likewise.
* gdb.base/info-shared-solib1.c: Likewise.
* gdb.base/info-shared-solib2.c: Likewise.
diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h
index 4e4f875..f678702 100644
--- a/gdb/breakpoint.h
+++ b/gdb/breakpoint.h
@@ -1515,6 +1515,4 @@ extern int user_breakpoint_p (struct breakpoint *);
/* Attempt to determine architecture of location identified by SAL. */
extern struct gdbarch *get_sal_arch (struct symtab_and_line sal);
-extern void handle_solib_event (void);
-
#endif /* !defined (BREAKPOINT_H) */
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index 6b9faf3..51c98a7 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -5205,7 +5205,7 @@ bpstat_stop_status (struct address_space *aspace,
{
if (bs->breakpoint_at && bs->breakpoint_at->type == bp_shlib_event)
{
- handle_solib_event ();
+ handle_solib_event (bs);
break;
}
}
@@ -5301,25 +5301,6 @@ handle_jit_event (void)
target_terminal_inferior ();
}
-/* Handle an solib event by calling solib_add. */
-
-void
-handle_solib_event (void)
-{
- clear_program_space_solib_cache (current_inferior ()->pspace);
-
- /* Check for any newly added shared libraries if we're supposed to
- be adding them automatically. Switch terminal for any messages
- produced by breakpoint_re_set. */
- target_terminal_ours_for_output ();
-#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 ();
-}
-
/* Prepare WHAT final decision for infrun. */
/* Decide what infrun needs to do with this bpstat. */
diff --git a/gdb/solib.h b/gdb/solib.h
index 65e3857..6e92ddc 100644
--- a/gdb/solib.h
+++ b/gdb/solib.h
@@ -21,6 +21,9 @@
#ifndef SOLIB_H
#define SOLIB_H
+/* For bpstat. */
+#include "breakpoint.h"
+
/* Forward decl's for prototypes */
struct so_list;
struct target_ops;
@@ -91,6 +94,13 @@ extern CORE_ADDR gdb_bfd_lookup_symbol_from_symtab (bfd *abfd,
void *),
void *data);
+/* Handle an solib event by calling solib_add. Targets which handle
+ solib events using breakpoints must pass a valid bpstat. Targets
+ which handle solib events using some other mechanism should pass
+ NULL. */
+
+extern void handle_solib_event (bpstat bs);
+
/* Enable or disable optional solib event breakpoints as appropriate. */
extern void update_solib_breakpoints (void);
diff --git a/gdb/solib.c b/gdb/solib.c
index dda0130..072fe4d 100644
--- a/gdb/solib.c
+++ b/gdb/solib.c
@@ -1212,6 +1212,30 @@ no_shared_libraries (char *ignored, int from_tty)
/* See solib.h. */
void
+handle_solib_event (bpstat bs)
+{
+ struct target_so_ops *ops = solib_ops (target_gdbarch);
+
+ if (ops->handle_solib_event != NULL)
+ ops->handle_solib_event (bs);
+
+ clear_program_space_solib_cache (current_inferior ()->pspace);
+
+ /* Check for any newly added shared libraries if we're supposed to
+ be adding them automatically. Switch terminal for any messages
+ produced by breakpoint_re_set. */
+ target_terminal_ours_for_output ();
+#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 ();
+}
+
+/* See solib.h. */
+
+void
update_solib_breakpoints (void)
{
struct target_so_ops *ops = solib_ops (target_gdbarch);
diff --git a/gdb/infrun.c b/gdb/infrun.c
index 89fbcfc..7c621ca 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -3318,7 +3318,7 @@ handle_inferior_event (struct execution_control_state *ecs)
context_switch (ecs->ptid);
regcache = get_thread_regcache (ecs->ptid);
- handle_solib_event ();
+ handle_solib_event (NULL);
ecs->event_thread->control.stop_bpstat
= bpstat_stop_status (get_regcache_aspace (regcache),
diff --git a/gdb/solist.h b/gdb/solist.h
index 0d9046d..ea580a9 100644
--- a/gdb/solist.h
+++ b/gdb/solist.h
@@ -23,6 +23,8 @@
#define SO_NAME_MAX_PATH_SIZE 512 /* FIXME: Should be dynamic */
/* For domain_enum domain. */
#include "symtab.h"
+/* For bpstat. */
+#include "breakpoint.h"
/* Forward declaration for target specific link map information. This
struct is opaque to all but the target specific file. */
@@ -150,6 +152,13 @@ struct target_so_ops
int (*keep_data_in_core) (CORE_ADDR vaddr,
unsigned long size);
+ /* Target-specific handling of solib events. For targets which
+ handle solib events using breakpoints a valid bpstat must be
+ passed. Targets which handle solib events using some other
+ mechanism should pass NULL. This pointer can be NULL, in which
+ case no specific handling is necessary for this target. */
+ void (*handle_solib_event) (bpstat bs);
+
/* Enable or disable optional solib event breakpoints as
appropriate. This should be called whenever
stop_on_solib_events is changed. This pointer can be
diff --git a/gdb/solib-svr4.c b/gdb/solib-svr4.c
index c111f04..ebb8c3c 100644
--- a/gdb/solib-svr4.c
+++ b/gdb/solib-svr4.c
@@ -52,6 +52,7 @@
static struct link_map_offsets *svr4_fetch_link_map_offsets (void);
static int svr4_have_link_map_offsets (void);
static void svr4_relocate_main_executable (void);
+static void svr4_free_library_list (void *p_list);
/* Link map info to include in an allocated so_list entry. */
@@ -94,6 +95,25 @@ static const char * const solib_break_names[] =
NULL
};
+/* What to do with the link_map cache. */
+
+enum probe_action
+ {
+ /* No action is required. The cache is still valid. */
+ LM_CACHE_NO_ACTION,
+
+ /* Something went wrong. The cache may be invalid and must be
+ cleared. Do not attempt further caching at this stop. */
+ LM_CACHE_INVALIDATE,
+
+ /* The cache should be reloaded now. */
+ LM_CACHE_RELOAD,
+
+ /* Attempt to incrementally update the cache. If the update
+ fails or is not possible, fall back to LM_CACHE_RELOAD. */
+ LM_CACHE_UPDATE_OR_RELOAD
+ };
+
/* A list of named probes which, if present in the dynamic linker,
allow more fine-grained breakpoints to be placed on shared library
events. */
@@ -106,16 +126,20 @@ struct probe_info
/* Nonzero if this probe must be stopped at even when
stop-on-solib-events is off. */
int mandatory;
+
+ /* What to do with the link_map cache when a breakpoint at this
+ probe is hit. */
+ enum probe_action action;
};
static const struct probe_info probe_info[] =
{
- { "init_start", 0 },
- { "init_complete", 1 },
- { "map_start", 0 },
- { "reloc_complete", 1 },
- { "unmap_start", 0 },
- { "unmap_complete", 1 },
+ { "init_start", 0, LM_CACHE_NO_ACTION },
+ { "init_complete", 1, LM_CACHE_RELOAD },
+ { "map_start", 0, LM_CACHE_NO_ACTION },
+ { "reloc_complete", 1, LM_CACHE_UPDATE_OR_RELOAD },
+ { "unmap_start", 0, LM_CACHE_NO_ACTION },
+ { "unmap_complete", 1, LM_CACHE_RELOAD },
};
#define NUM_PROBES ARRAY_SIZE (probe_info)
@@ -347,6 +371,10 @@ struct svr4_info
/* Named probes in the dynamic linker. */
VEC (probe_p) *probes[NUM_PROBES];
+
+ /* List of objects loaded from the inferior, used by the
+ probes-based interface to support incremental updates. */
+ struct so_list *solib_cache;
};
/* Per-program-space data key. */
@@ -365,6 +393,18 @@ free_probes (struct svr4_info *info)
memset (info->probes, 0, sizeof (info->probes));
}
+/* Free any cached solibs. */
+
+static void
+free_solib_cache (struct svr4_info *info)
+{
+ if (info->solib_cache == NULL)
+ return;
+
+ svr4_free_library_list (&info->solib_cache);
+ info->solib_cache = NULL;
+}
+
static void
svr4_pspace_data_cleanup (struct program_space *pspace, void *arg)
{
@@ -375,6 +415,7 @@ svr4_pspace_data_cleanup (struct program_space *pspace, void *arg)
return;
free_probes (info);
+ free_solib_cache (info);
xfree (info);
}
@@ -1036,6 +1077,36 @@ svr4_free_library_list (void *p_list)
}
}
+/* Copy library list. */
+
+static struct so_list *
+svr4_copy_library_list (struct so_list *src)
+{
+ struct link_map_offsets *lmo = svr4_fetch_link_map_offsets ();
+ struct so_list *dst = NULL;
+ struct so_list **link = &dst;
+
+ while (src != NULL)
+ {
+ struct so_list *new;
+
+ new = XZALLOC (struct so_list);
+
+ memcpy (new, src, sizeof (struct so_list));
+
+ new->lm_info = xmalloc (lmo->link_map_size);
+ memcpy (new->lm_info, src->lm_info, lmo->link_map_size);
+
+ new->next = NULL;
+ *link = new;
+ link = &new->next;
+
+ src = src->next;
+ }
+
+ return dst;
+}
+
#ifdef HAVE_LIBEXPAT
#include "xml-support.h"
@@ -1215,15 +1286,17 @@ svr4_default_sos (void)
return new;
}
-/* Read the whole inferior libraries chain starting at address LM. Add the
- entries to the tail referenced by LINK_PTR_PTR. Ignore the first entry if
- IGNORE_FIRST and set global MAIN_LM_ADDR according to it. */
+/* Read the whole inferior libraries chain starting at address LM.
+ Expect the first entry in the chain's previous entry to be PREV_LM.
+ Add the entries to the tail referenced by LINK_PTR_PTR. Ignore the
+ first entry if IGNORE_FIRST and set global MAIN_LM_ADDR according
+ to it. Returns nonzero upon success. */
-static void
-svr4_read_so_list (CORE_ADDR lm, struct so_list ***link_ptr_ptr,
- int ignore_first)
+static int
+svr4_read_so_list (CORE_ADDR lm, CORE_ADDR prev_lm,
+ struct so_list ***link_ptr_ptr, int ignore_first)
{
- CORE_ADDR prev_lm = 0, next_lm;
+ CORE_ADDR next_lm;
for (; lm != 0; prev_lm = lm, lm = next_lm)
{
@@ -1240,7 +1313,7 @@ svr4_read_so_list (CORE_ADDR lm, struct so_list ***link_ptr_ptr,
if (new->lm_info == NULL)
{
do_cleanups (old_chain);
- break;
+ return 0;
}
next_lm = new->lm_info->l_next;
@@ -1251,7 +1324,7 @@ svr4_read_so_list (CORE_ADDR lm, struct so_list ***link_ptr_ptr,
paddress (target_gdbarch, prev_lm),
paddress (target_gdbarch, new->lm_info->l_prev));
do_cleanups (old_chain);
- break;
+ return 0;
}
/* For SVR4 versions, the first entry in the link map is for the
@@ -1297,6 +1370,8 @@ svr4_read_so_list (CORE_ADDR lm, struct so_list ***link_ptr_ptr,
**link_ptr_ptr = new;
*link_ptr_ptr = &new->next;
}
+
+ return 1;
}
/* Implement the "current_sos" target_so_ops method. */
@@ -1333,6 +1408,10 @@ svr4_current_sos (void)
info = get_svr4_info ();
+ /* If we have a cached result then return a copy. */
+ if (info->solib_cache != NULL)
+ return svr4_copy_library_list (info->solib_cache);
+
/* Always locate the debug struct, in case it has moved. */
info->debug_base = 0;
locate_base (info);
@@ -1355,7 +1434,7 @@ svr4_current_sos (void)
`struct so_list' nodes. */
lm = solib_svr4_r_map (info);
if (lm)
- svr4_read_so_list (lm, &link_ptr, ignore_first);
+ svr4_read_so_list (lm, 0, &link_ptr, ignore_first);
/* On Solaris, the dynamic linker is not in the normal list of
shared objects, so make sure we pick it up too. Having
@@ -1363,7 +1442,7 @@ svr4_current_sos (void)
for skipping dynamic linker resolver code. */
lm = solib_svr4_r_ldsomap (info);
if (lm)
- svr4_read_so_list (lm, &link_ptr, 0);
+ svr4_read_so_list (lm, 0, &link_ptr, 0);
discard_cleanups (back_to);
@@ -1494,6 +1573,146 @@ solib_event_probe_at (struct bp_location *loc, struct probe_and_info *result)
return NULL;
}
+/* Decide what action to take when the specified solib event probe is
+ hit. */
+
+static enum probe_action
+solib_event_probe_action (struct probe_and_info *pi)
+{
+ enum probe_action action;
+ int update;
+ struct obj_section *os;
+ unsigned probe_argc;
+ struct svr4_info *info;
+ CORE_ADDR debug_base;
+
+ action = pi->info->action;
+ if (action == LM_CACHE_NO_ACTION || action == LM_CACHE_INVALIDATE)
+ return action;
+
+ gdb_assert (action == LM_CACHE_RELOAD
+ || action == LM_CACHE_UPDATE_OR_RELOAD);
+
+ os = find_pc_section (pi->probe->address);
+ if (os == NULL)
+ return LM_CACHE_INVALIDATE;
+
+ /* Check that an appropriate number of arguments has been supplied.
+ We expect:
+ arg1: Lmid_t lmid (mandatory)
+ arg2: struct r_debug *r_debug (mandatory)
+ arg3: struct link_map *new (optional, for incremental updates) */
+ probe_argc = get_probe_argument_count (os->objfile, pi->probe);
+ if (probe_argc == 2)
+ action = LM_CACHE_RELOAD;
+ else if (probe_argc < 2)
+ return LM_CACHE_INVALIDATE;
+
+ /* We only currently support the global namespace (PR gdb/11839).
+ If the probe's r_debug doesn't match the global r_debug then
+ this event refers to some other namespace and must be ignored. */
+ info = get_svr4_info ();
+
+ /* Always locate the debug struct, in case it has moved. */
+ info->debug_base = 0;
+ locate_base (info);
+
+ debug_base = value_as_address (evaluate_probe_argument (os->objfile,
+ pi->probe, 1));
+
+ if (debug_base != info->debug_base)
+ return LM_CACHE_NO_ACTION;
+
+ return action;
+}
+
+/* Populate the solib cache with by reading the entire list of shared
+ objects from the inferior. */
+
+static void
+solib_cache_update_full (void)
+{
+ struct svr4_info *info = get_svr4_info ();
+
+ gdb_assert (info->solib_cache == NULL);
+ info->solib_cache = svr4_current_sos ();
+}
+
+/* Update the solib cache starting from the link-map supplied by the
+ linker in the probe's third argument. Returns nonzero if the list
+ was successfully updated, or zero to indicate failure. */
+
+static int
+solib_cache_update_incremental (struct probe_and_info *pi)
+{
+ struct svr4_info *info = get_svr4_info ();
+ struct so_list *tail, **link;
+ struct obj_section *os;
+ CORE_ADDR lm;
+
+ if (info->solib_cache == NULL)
+ return 0;
+
+ tail = info->solib_cache;
+ while (tail->next)
+ tail = tail->next;
+ link = &tail->next;
+
+ os = find_pc_section (pi->probe->address);
+ if (os == NULL)
+ return 0;
+
+ lm = value_as_address (evaluate_probe_argument (os->objfile,
+ pi->probe, 2));
+
+ if (lm == 0)
+ return 0;
+
+ return svr4_read_so_list (lm, tail->lm_info->lm_addr, &link, 0);
+}
+
+/* Update the solib cache as appropriate when using the probes-based
+ linker interface. Do nothing if using the standard interface. */
+
+static void
+svr4_handle_solib_event (bpstat bs)
+{
+ struct svr4_info *info = get_svr4_info ();
+ struct probe_and_info buf, *pi;
+ enum probe_action action;
+
+ /* It is possible that this function will be called incorrectly
+ by the handle_solib_event in handle_inferior_event if GDB goes
+ fully multi-target. */
+ gdb_assert (bs != NULL);
+
+ if (!info->using_probes)
+ return;
+
+ pi = solib_event_probe_at (bs->bp_location_at, &buf);
+ if (pi == NULL)
+ action = LM_CACHE_INVALIDATE; /* Should never happen. */
+ else
+ action = solib_event_probe_action (pi);
+
+ if (action == LM_CACHE_NO_ACTION)
+ return;
+
+ if (action == LM_CACHE_UPDATE_OR_RELOAD)
+ {
+ if (solib_cache_update_incremental (pi))
+ return;
+
+ action = LM_CACHE_RELOAD;
+ }
+
+ free_solib_cache (info);
+ if (action == LM_CACHE_INVALIDATE)
+ return;
+
+ solib_cache_update_full ();
+}
+
/* Helper function for svr4_update_solib_event_breakpoints. */
static int
@@ -2446,6 +2665,9 @@ svr4_solib_create_inferior_hook (int from_tty)
info = get_svr4_info ();
+ /* Free any solibs cached by the probes-based linker interface. */
+ free_solib_cache (info);
+
/* Relocate the main executable if necessary. */
svr4_relocate_main_executable ();
@@ -2712,5 +2934,6 @@ _initialize_svr4_solib (void)
svr4_so_ops.lookup_lib_global_symbol = elf_lookup_lib_symbol;
svr4_so_ops.same = svr4_same;
svr4_so_ops.keep_data_in_core = svr4_keep_data_in_core;
+ svr4_so_ops.handle_solib_event = svr4_handle_solib_event;
svr4_so_ops.update_breakpoints = svr4_update_solib_event_breakpoints;
}
diff --git a/gdb/testsuite/gdb.base/info-shared-solib1.c b/gdb/testsuite/gdb.base/info-shared-solib1.c
new file mode 100644
index 0000000..9979ee7
--- /dev/null
+++ b/gdb/testsuite/gdb.base/info-shared-solib1.c
@@ -0,0 +1,24 @@
+/* Copyright 2012 Free Software Foundation, Inc.
+
+ 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 3 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, see <http://www.gnu.org/licenses/>. */
+
+#include <stdio.h>
+
+int
+foo (int n)
+{
+ printf ("foo %d\n", n);
+
+ return 0;
+}
diff --git a/gdb/testsuite/gdb.base/info-shared-solib2.c b/gdb/testsuite/gdb.base/info-shared-solib2.c
new file mode 100644
index 0000000..d4ed1e6
--- /dev/null
+++ b/gdb/testsuite/gdb.base/info-shared-solib2.c
@@ -0,0 +1,24 @@
+/* Copyright 2012 Free Software Foundation, Inc.
+
+ 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 3 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, see <http://www.gnu.org/licenses/>. */
+
+#include <stdio.h>
+
+int
+bar (int n)
+{
+ printf ("bar %d\n", n);
+
+ return 0;
+}
diff --git a/gdb/testsuite/gdb.base/info-shared.c b/gdb/testsuite/gdb.base/info-shared.c
new file mode 100644
index 0000000..d699a11
--- /dev/null
+++ b/gdb/testsuite/gdb.base/info-shared.c
@@ -0,0 +1,48 @@
+/* Copyright 2012 Free Software Foundation, Inc.
+
+ 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 3 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, see <http://www.gnu.org/licenses/>. */
+
+#include <dlfcn.h>
+
+void
+stop ()
+{
+}
+
+int
+main ()
+{
+ void *handle1, *handle2;
+ void (*func)(int);
+
+ handle1 = dlopen (SHLIB1_NAME, RTLD_LAZY);
+ stop ();
+
+ handle2 = dlopen (SHLIB2_NAME, RTLD_LAZY);
+ stop ();
+
+ func = (void (*)(int)) dlsym (handle1, "foo");
+ func (1);
+
+ func = (void (*)(int)) dlsym (handle2, "bar");
+ func (2);
+
+ dlclose (handle1);
+ stop ();
+
+ dlclose (handle2);
+ stop ();
+
+ return 0;
+}
diff --git a/gdb/testsuite/gdb.base/info-shared.exp b/gdb/testsuite/gdb.base/info-shared.exp
new file mode 100644
index 0000000..f3a74c6
--- /dev/null
+++ b/gdb/testsuite/gdb.base/info-shared.exp
@@ -0,0 +1,139 @@
+# Copyright 2012 Free Software Foundation, Inc.
+
+# 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 3 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, see <http://www.gnu.org/licenses/>.
+
+if { [skip_shlib_tests] || [is_remote target] } {
+ return 0
+}
+
+standard_testfile
+
+set lib1name $testfile-solib1
+set srcfile_lib1 $srcdir/$subdir/$lib1name.c
+set binfile_lib1 [standard_output_file $lib1name.so]
+set define1 -DSHLIB1_NAME\=\"$binfile_lib1\"
+
+set lib2name $testfile-solib2
+set srcfile_lib2 $srcdir/$subdir/$lib2name.c
+set binfile_lib2 [standard_output_file $lib2name.so]
+set define2 -DSHLIB2_NAME\=\"$binfile_lib2\"
+
+if { [gdb_compile_shlib $srcfile_lib1 $binfile_lib1 \
+ [list additional_flags=-fPIC]] != "" } {
+ untested "Could not compile $binfile_lib1."
+ return -1
+}
+
+if { [gdb_compile_shlib $srcfile_lib2 $binfile_lib2 \
+ [list additional_flags=-fPIC]] != "" } {
+ untested "Could not compile $binfile_lib2."
+ return -1
+}
+
+set cflags "$define1 $define2"
+if { [prepare_for_testing $testfile.exp $testfile $srcfile \
+ [list additional_flags=$cflags libs=-ldl]] } {
+ return -1
+}
+
+# Run "info sharedlibrary" and check for the presence or absence of
+# our libraries.
+proc check_info_shared { test expect1 expect2 } {
+ global lib1name
+ global lib2name
+ global gdb_prompt
+
+ set actual1 0
+ set actual2 0
+
+ gdb_test_multiple "info sharedlibrary" $test {
+ -re $lib1name {
+ set actual1 1
+ exp_continue
+ }
+ -re $lib2name {
+ set actual2 1
+ exp_continue
+ }
+ -re "\r\n$gdb_prompt $" {
+ if { $actual1 == $expect1 && $actual2 == $expect2 } {
+ pass $test
+ } else {
+ fail $test
+ }
+ }
+ }
+}
+
+# Set up breakpoints.
+gdb_test "break stop" {Breakpoint [0-9]+ at .*}
+gdb_test_no_output "set breakpoint pending on"
+gdb_test "break foo" {Breakpoint [0-9]+ \(foo\) pending\.}
+gdb_test "break bar" {Breakpoint [0-9]+ \(bar\) pending\.}
+
+# Check neither of the libraries are loaded at the start.
+gdb_test "start" {Temporary breakpoint [0-9]+, .* in main \(\)}
+check_info_shared "info sharedlibrary #1" 0 0
+
+# Run to the first stop and check that only the first library is loaded.
+gdb_test "c" {Breakpoint [0-9]+, .* in stop \(\)}
+check_info_shared "info sharedlibrary #2" 1 0
+
+# Run to the second stop and check that both libraries are loaded.
+gdb_test "c" {Breakpoint [0-9]+, .* in stop \(\)}
+check_info_shared "info sharedlibrary #3" 1 1
+
+# Check that the next stop is in foo.
+gdb_test "c" {Breakpoint [0-9]+, .* in foo \(\) from .*}
+
+# Check that the next stop is in bar.
+gdb_test "c" {Breakpoint [0-9]+, .* in bar \(\) from .*}
+
+# Restart the inferior and make sure there are no breakpoint reset
+# errors. These can happen with the probes-based runtime linker
+# interface if the cache is not cleared correctly.
+set test "restart"
+gdb_test_multiple "run" $test {
+ -re {Start it from the beginning\? \(y or n\) } {
+ send_gdb "y\n"
+ exp_continue
+ }
+ -re {Error in re-setting breakpoint} {
+ fail $test
+ }
+ -re "\r\n$gdb_prompt $" {
+ pass $test
+ }
+}
+
+# We're at the first stop. Check that only the first library is loaded.
+check_info_shared "info sharedlibrary #4" 1 0
+
+# Run to the second stop and check that both libraries are loaded.
+gdb_test "c" {Breakpoint [0-9]+, .* in stop \(\)}
+check_info_shared "info sharedlibrary #5" 1 1
+
+# Check that the next stop is in foo.
+gdb_test "c" {Breakpoint [0-9]+, .* in foo \(\) from .*}
+
+# Check that the next stop is in bar.
+gdb_test "c" {Breakpoint [0-9]+, .* in bar \(\) from .*}
+
+# Run to the next stop and check that the first library has been unloaded.
+gdb_test "c" {Breakpoint [0-9]+, .* in stop \(\)}
+check_info_shared "info sharedlibrary #6" 0 1
+
+# Run to the last stop and check that both libraries are gone.
+gdb_test "c" {Breakpoint [0-9]+, .* in stop \(\)}
+check_info_shared "info sharedlibrary #7" 0 0
More information about the Gdb-patches
mailing list