[RFC] Share the shared library list between inferiors

Pedro Alves
2008-10-27T23:29:39Z

[-- Attachment #1: Type: text/plain, Size: 1563 bytes --]

Hi,

(This is one of the last patches needed for correct
multi-process + non-stop debugging against Ericsson DICOS. This one
may turn out useful for some embedded OSs, when multi-process
support for them is added.)

When debugging against DICOS, we only need/should query the shared
library list (using solib-target.c) once on initial connection --- not
whenever we attach to a new process. (there's no notion of a main exec file
in DICOS, it's all shared libraries, with a bunch of possible entry points).
The same code is visible to all processes. Although each process
has it's own address space, all code is loaded/relocated to the same
addresses in all inferiors. It's like we're debugging a bunch of forks. The
debug API then goes a step further, and makes it so that an
inserted breakpoint is visible to all processes. Since both the
code and inserted breakpoint locations are visible to all processes, it is bad to
remove/clear them whenever we attach or detach to/from an inferior.

This patch teaches GDB about this property.

There are several ways to skin this cat. This one seemed like
the smallest, most extensible and malleable one from GDB's side, because
it doesn't cast to stone any new protocol extension --- which may
prove limited to some systems (some memory regions shared, others not;
some shared but visible at different addresses in different
inferiors/cores, etc.). I was hoping we'd cross that bridge when
we start seeing those systems reporting multi process support
to GDB.

What do people think about this?

--
Pedro Alves

[-- Attachment #2: global_solist.diff --]
[-- Type: text/x-diff, Size: 12995 bytes --]

2008-10-27 Pedro Alves <pedro@codesourcery.com>

* remote.c (remote_start_remote): If the solib list is global,
fetch libraries and insert breakpoints after connecting.
* infcmd.c (post_create_inferior): If the solist is shared between
inferiors, no need to refetch it on every new inferior.
(detach_command): If the shared library list is shared between
inferiors, then don't clear it on every inferior detach.
* gdbarch.sh (has_global_solist): New.
* i386-dicos-tdep.c (i386_dicos_init_abi): Set
gdbarch_has_global_solist.
* target.c (target_pre_inferior): If the shared library list is
shared between inferiors, then don't clear it here, neither
invalidate the memory regions or clear the target description.
(target_detach): If the shared library list is shared between
inferiors, then don't remove breakpoints from the target here.
(target_disconnect): Remove breakpoints from the target here.
* solib.c (update_solib_list): Check for null_ptid.
* breakpoint.c (insert_breakpoints, update_global_location_list):
If the shared library list is shared between inferiors, insert
breakpoints even if there's no execution.
(breakpoint_init_inferior): If the shared library list is shared
between inferiors, don't delete breakpoints or mark them
uninserted here.

* gdbarch.c, gdbarch.h: Regenerate.

---
gdb/breakpoint.c | 17 +++++++++++++----
gdb/gdbarch.c | 23 +++++++++++++++++++++++
gdb/gdbarch.h | 6 ++++++
gdb/gdbarch.sh | 4 ++++
gdb/i386-dicos-tdep.c | 4 ++++
gdb/infcmd.c | 13 +++++++++++--
gdb/remote.c | 11 +++++++++++
gdb/solib.c | 2 +-
gdb/target.c | 29 +++++++++++++++++++++--------
9 files changed, 94 insertions(+), 15 deletions(-)

Index: src/gdb/remote.c
===================================================================
--- src.orig/gdb/remote.c 2008-10-27 22:40:09.000000000 +0000
+++ src/gdb/remote.c 2008-10-27 23:03:06.000000000 +0000
@@ -2554,6 +2554,11 @@ remote_start_remote (struct ui_out *uiou
getpkt (&rs->buf, &rs->buf_size, 0);
}

+ /* On OSs where the list of libraries is global to all
+ processes, we fetch them early. */
+ if (gdbarch_has_global_solist (target_gdbarch))
+ solib_add (NULL, args->from_tty, args->target, auto_solib_add);
+
/* Next, if the target can specify a description, read it. We do
this before anything involving memory or registers. */
target_find_description ();
@@ -2721,6 +2726,12 @@ remote_start_remote (struct ui_out *uiou
if (exec_bfd) /* No use without an exec file. */
remote_check_symbols (symfile_objfile);
}
+
+ /* If code is shared between processes, then breakpoints are global
+ too; Insert them now. */
+ if (gdbarch_has_global_solist (target_gdbarch)
+ && breakpoints_always_inserted_mode ())
+ insert_breakpoints ();
}

/* Open a connection to a remote debugger.
Index: src/gdb/infcmd.c
===================================================================
--- src.orig/gdb/infcmd.c 2008-10-27 20:38:49.000000000 +0000
+++ src/gdb/infcmd.c 2008-10-27 22:46:52.000000000 +0000
@@ -385,7 +385,9 @@ post_create_inferior (struct target_ops
don't need to. */
target_find_description ();

- if (exec_bfd)
+ /* If the solist is global across processes, there's no need to
+ refetch it here. */
+ if (exec_bfd && !gdbarch_has_global_solist (target_gdbarch))
{
/* Sometimes the platform-specific hook loads initial shared
libraries, and sometimes it doesn't. Try to do so first, so
@@ -397,7 +399,10 @@ post_create_inferior (struct target_ops
#else
solib_add (NULL, from_tty, target, auto_solib_add);
#endif
+ }

+ if (exec_bfd)
+ {
/* Create the hooks to handle shared library load and unload
events. */
#ifdef SOLIB_CREATE_INFERIOR_HOOK
@@ -2313,7 +2318,11 @@ detach_command (char *args, int from_tty
{
dont_repeat (); /* Not for the faint of heart. */
target_detach (args, from_tty);
- no_shared_libraries (NULL, from_tty);
+
+ /* If the solist is global across inferiors, don't clear it when we
+ detach from a single inferior. */
+ if (!gdbarch_has_global_solist (target_gdbarch))
+ no_shared_libraries (NULL, from_tty);

/* If the current target interface claims there's still execution,
then don't mess with threads of other processes. */
Index: src/gdb/gdbarch.c
===================================================================
--- src.orig/gdb/gdbarch.c 2008-10-27 20:38:28.000000000 +0000
+++ src/gdb/gdbarch.c 2008-10-27 22:40:31.000000000 +0000
@@ -240,6 +240,7 @@ struct gdbarch
gdbarch_target_signal_from_host_ftype *target_signal_from_host;
gdbarch_target_signal_to_host_ftype *target_signal_to_host;
gdbarch_record_special_symbol_ftype *record_special_symbol;
+ int has_global_solist;
};

@@ -371,6 +372,7 @@ struct gdbarch startup_gdbarch =
default_target_signal_from_host, /* target_signal_from_host */
default_target_signal_to_host, /* target_signal_to_host */
0, /* record_special_symbol */
+ 0, /* has_global_solist */
/* startup_gdbarch() */
};

@@ -623,6 +625,7 @@ verify_gdbarch (struct gdbarch *gdbarch)
/* Skip verify of target_signal_from_host, invalid_p == 0 */
/* Skip verify of target_signal_to_host, invalid_p == 0 */
/* Skip verify of record_special_symbol, has predicate */
+ /* Skip verify of has_global_solist, invalid_p == 0 */
buf = ui_file_xstrdup (log, &dummy);
make_cleanup (xfree, buf);
if (strlen (buf) > 0)
@@ -832,6 +835,9 @@ gdbarch_dump (struct gdbarch *gdbarch, s
"gdbarch_dump: get_longjmp_target = <0x%lx>\n",
(long) gdbarch->get_longjmp_target);
fprintf_unfiltered (file,
+ "gdbarch_dump: has_global_solist = %s\n",
+ plongest (gdbarch->has_global_solist));
+ fprintf_unfiltered (file,
"gdbarch_dump: have_nonsteppable_watchpoint = %s\n",
plongest (gdbarch->have_nonsteppable_watchpoint));
fprintf_unfiltered (file,
@@ -3237,6 +3243,23 @@ set_gdbarch_record_special_symbol (struc
gdbarch->record_special_symbol = record_special_symbol;
}

+int
+gdbarch_has_global_solist (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ /* Skip verify of has_global_solist, invalid_p == 0 */
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_has_global_solist called\n");
+ return gdbarch->has_global_solist;
+}
+
+void
+set_gdbarch_has_global_solist (struct gdbarch *gdbarch,
+ int has_global_solist)
+{
+ gdbarch->has_global_solist = has_global_solist;
+}
+

/* Keep a registry of per-architecture data-pointers required by GDB
modules. */
Index: src/gdb/gdbarch.h
===================================================================
--- src.orig/gdb/gdbarch.h 2008-10-27 20:38:28.000000000 +0000
+++ src/gdb/gdbarch.h 2008-10-27 22:40:31.000000000 +0000
@@ -811,6 +811,12 @@ typedef void (gdbarch_record_special_sym
extern void gdbarch_record_special_symbol (struct gdbarch *gdbarch, struct objfile *objfile, asymbol *sym);
extern void set_gdbarch_record_special_symbol (struct gdbarch *gdbarch, gdbarch_record_special_symbol_ftype *record_special_symbol);

+/* True if the list of shared libraries is one and only for all
+ processes, as opposed to a list of shared libraries per inferior. */
+
+extern int gdbarch_has_global_solist (struct gdbarch *gdbarch);
+extern void set_gdbarch_has_global_solist (struct gdbarch *gdbarch, int has_global_solist);
+
extern struct gdbarch_tdep *gdbarch_tdep (struct gdbarch *gdbarch);

Index: src/gdb/gdbarch.sh
===================================================================
--- src.orig/gdb/gdbarch.sh 2008-10-27 20:38:28.000000000 +0000
+++ src/gdb/gdbarch.sh 2008-10-27 22:40:31.000000000 +0000
@@ -707,6 +707,10 @@ m:int:target_signal_to_host:enum target_

# Record architecture-specific information from the symbol table.
M:void:record_special_symbol:struct objfile *objfile, asymbol *sym:objfile, sym
+
+# True if the list of shared libraries is one and only for all
+# processes, as opposed to a list of shared libraries per inferior.
+v:int:has_global_solist:::0:0::0
EOF
}

Index: src/gdb/i386-dicos-tdep.c
===================================================================
--- src.orig/gdb/i386-dicos-tdep.c 2008-10-27 20:38:28.000000000 +0000
+++ src/gdb/i386-dicos-tdep.c 2008-10-27 22:40:31.000000000 +0000
@@ -49,6 +49,10 @@ i386_dicos_init_abi (struct gdbarch_info

set_solib_ops (gdbarch, &solib_target_so_ops);

+ /* Every process, although has its own address space, sees the same
+ list of shared libraries. */
+ set_gdbarch_has_global_solist (gdbarch, 1);
+
/* There's no (standard definition of) entry point or a guaranteed
text location we could find with a symbol where to place the call
dummy, so we put it on the stack. */
Index: src/gdb/target.c
===================================================================
--- src.orig/gdb/target.c 2008-10-27 22:40:09.000000000 +0000
+++ src/gdb/target.c 2008-10-27 22:40:31.000000000 +0000
@@ -1756,11 +1756,18 @@ target_pre_inferior (int from_tty)
(gdb) attach 4712
Cannot access memory at address 0xdeadbeef
*/
- no_shared_libraries (NULL, from_tty);

- invalidate_target_mem_regions ();
+ /* In some OSs, the shared library list is the same/global/shared
+ across inferiors. If code is shared between processes, so are
+ memory regions and features. */
+ if (!gdbarch_has_global_solist (target_gdbarch))
+ {
+ no_shared_libraries (NULL, from_tty);
+
+ invalidate_target_mem_regions ();

- target_clear_description ();
+ target_clear_description ();
+ }
}

/* This is to be called by the open routine before it does
@@ -1794,9 +1801,14 @@ target_preopen (int from_tty)
void
target_detach (char *args, int from_tty)
{
- /* If we're in breakpoints-always-inserted mode, have to
- remove them before detaching. */
- remove_breakpoints ();
+ if (gdbarch_has_global_solist (target_gdbarch))
+ /* Don't remove global breakpoints here. They're removed on
+ disconnection from the target. */
+ ;
+ else
+ /* If we're in breakpoints-always-inserted mode, have to remove
+ them before detaching. */
+ remove_breakpoints ();

(current_target.to_detach) (args, from_tty);
}
@@ -1806,8 +1818,9 @@ target_disconnect (char *args, int from_
{
struct target_ops *t;

- /* If we're in breakpoints-always-inserted mode, have to
- remove them before disconnecting. */
+ /* If we're in breakpoints-always-inserted mode or if breakpoints
+ are global across processes, we have to remove them before
+ disconnecting. */
remove_breakpoints ();

for (t = current_target.beneath; t != NULL; t = t->beneath)
Index: src/gdb/solib.c
===================================================================
--- src.orig/gdb/solib.c 2008-10-27 20:38:28.000000000 +0000
+++ src/gdb/solib.c 2008-10-27 22:40:31.000000000 +0000
@@ -510,7 +510,7 @@ update_solib_list (int from_tty, struct

/* We can reach here due to changing solib-search-path or the
sysroot, before having any inferior. */
- if (target_has_execution)
+ if (target_has_execution && !ptid_equal (inferior_ptid, null_ptid))
{
struct inferior *inf = current_inferior ();

Index: src/gdb/breakpoint.c
===================================================================
--- src.orig/gdb/breakpoint.c 2008-10-27 20:38:28.000000000 +0000
+++ src/gdb/breakpoint.c 2008-10-27 22:42:16.000000000 +0000
@@ -1274,7 +1274,10 @@ insert_breakpoints (void)

update_global_location_list (1);

- if (!breakpoints_always_inserted_mode () && target_has_execution)
+ if (!breakpoints_always_inserted_mode ()
+ && (target_has_execution
+ || (gdbarch_has_global_solist (target_gdbarch)
+ && target_supports_multi_process ())))
/* update_global_location_list does not insert breakpoints
when always_inserted_mode is not enabled. Explicitly
insert them now. */
@@ -1743,6 +1746,11 @@ breakpoint_init_inferior (enum inf_conte
struct bp_location *bpt;
int ix;

+ /* If breakpoint locations are shared across processes, then there's
+ nothing to do. */
+ if (gdbarch_has_global_solist (target_gdbarch))
+ return;
+
ALL_BP_LOCATIONS (bpt)
if (bpt->owner->enable_state != bp_permanent)
bpt->inserted = 0;
@@ -7272,9 +7280,10 @@ update_global_location_list (int should_
check_duplicates (b);
}

- if (breakpoints_always_inserted_mode ()
- && should_insert
- && target_has_execution)
+ if (breakpoints_always_inserted_mode () && should_insert
+ && (target_has_execution
+ || (gdbarch_has_global_solist (target_gdbarch)
+ && target_supports_multi_process ())))
insert_breakpoint_locations ();
}