From: Gary Benson <gbenson@redhat.com>
To: gdb-patches@sourceware.org
Subject: [RFA 4/4] Improved linker-debugger interface
Date: Thu, 12 Jul 2012 12:36:00 -0000 [thread overview]
Message-ID: <20120712123617.GE29236@redhat.com> (raw)
In-Reply-To: <20120712123406.GA29236@redhat.com>
[-- Attachment #1: Type: text/plain, Size: 835 bytes --]
Hi all,
This patch builds on the probes-based runtime linker interface,
adding incremental library list loading. The list of currently
loaded libraries is cached in the program space, and updated as
necessary whenever a solib event breakpoint is hit. I've tried
to make it fail as gracefully as possible for maximum forward
compatibility: if something happens that it does not understand
then the cache will be wiped and not repopulated until an event
occurs that it does understand. Until such time GDB will use
its previous behaviour of walking the entire link map each time
a solib event occurs.
I have of course tested this locally, but I don't have a real
world example of an application using thousands of shared
libraries, so I'd really appreciate feedback from those of you
that do.
Cheers,
Gary
--
http://gbenson.net/
[-- Attachment #2: rtld-stap-3.patch --]
[-- Type: text/plain, Size: 25805 bytes --]
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 $objdir/$subdir/$lib1name.so
+set define1 -DSHLIB1_NAME\=\"$binfile_lib1\"
+
+set lib2name $testfile-solib2
+set srcfile_lib2 $srcdir/$subdir/$lib2name.c
+set binfile_lib2 $objdir/$subdir/$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
next prev parent reply other threads:[~2012-07-12 12:36 UTC|newest]
Thread overview: 19+ messages / expand[flat|nested] mbox.gz Atom feed top
2012-07-12 12:34 [RFA 0/4] " Gary Benson
2012-07-12 12:35 ` [RFA 1/4] " Gary Benson
2012-07-12 12:36 ` Gary Benson [this message]
2012-07-13 9:42 ` [RFA 4/4] " Gary Benson
2012-07-13 12:20 ` Gary Benson
2012-07-17 18:11 ` Sergio Durigan Junior
2012-07-18 14:28 ` Jan Kratochvil
2012-07-18 15:11 ` Sergio Durigan Junior
2012-07-19 14:38 ` Gary Benson
2012-07-12 12:36 ` [RFA 2/4] " Gary Benson
2012-07-13 9:41 ` Gary Benson
2012-07-12 12:36 ` [RFA 3/4] " Gary Benson
2012-07-17 18:01 ` Sergio Durigan Junior
2012-07-17 21:57 ` Jan Kratochvil
2012-07-17 23:42 ` Sergio Durigan Junior
2012-07-18 7:02 ` Jan Kratochvil
2012-07-18 10:36 ` Gary Benson
2012-07-19 14:36 ` Gary Benson
2012-07-18 14:08 ` [RFA 0/4] " Gary Benson
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20120712123617.GE29236@redhat.com \
--to=gbenson@redhat.com \
--cc=gdb-patches@sourceware.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox