/* libthread_db assisted debugging support, generic parts.
- Copyright (C) 1999-2021 Free Software Foundation, Inc.
+ Copyright (C) 1999-2022 Free Software Foundation, Inc.
This file is part of GDB.
ptid_t wait (ptid_t, struct target_waitstatus *, target_wait_flags) override;
void resume (ptid_t, int, enum gdb_signal) override;
void mourn_inferior () override;
+ void follow_exec (inferior *, ptid_t, const char *) override;
void update_thread_list () override;
std::string pid_to_str (ptid_t) override;
CORE_ADDR get_thread_local_address (ptid_t ptid,
CORE_ADDR load_module_addr,
CORE_ADDR offset) override;
const char *extra_thread_info (struct thread_info *) override;
- ptid_t get_ada_task_ptid (long lwp, long thread) override;
+ ptid_t get_ada_task_ptid (long lwp, ULONGEST thread) override;
thread_info *thread_handle_to_thread_info (const gdb_byte *thread_handle,
int handle_len,
gdb::byte_vector thread_info_to_thread_handle (struct thread_info *) override;
};
-static char *libthread_db_search_path;
+static std::string libthread_db_search_path = LIBTHREAD_DB_SEARCH_PATH;
/* Set to true if thread_db auto-loading is enabled
by the "set auto-load libthread-db" command. */
show_auto_load_thread_db (struct ui_file *file, int from_tty,
struct cmd_list_element *c, const char *value)
{
- fprintf_filtered (file, _("Auto-loading of inferior specific libthread_db "
- "is %s.\n"),
- value);
+ gdb_printf (file, _("Auto-loading of inferior specific libthread_db "
+ "is %s.\n"),
+ value);
}
static void
set_libthread_db_search_path (const char *ignored, int from_tty,
struct cmd_list_element *c)
{
- if (*libthread_db_search_path == '\0')
- {
- xfree (libthread_db_search_path);
- libthread_db_search_path = xstrdup (LIBTHREAD_DB_SEARCH_PATH);
- }
+ if (libthread_db_search_path.empty ())
+ libthread_db_search_path = LIBTHREAD_DB_SEARCH_PATH;
}
/* If non-zero, print details of libthread_db processing. */
show_libthread_db_debug (struct ui_file *file, int from_tty,
struct cmd_list_element *c, const char *value)
{
- fprintf_filtered (file, _("libthread-db debugging is %s.\n"), value);
+ gdb_printf (file, _("libthread-db debugging is %s.\n"), value);
}
/* If we're running on GNU/Linux, we must explicitly attach to any new
/* Non-zero if we have determined the signals used by the threads
library. */
static int thread_signals;
-static sigset_t thread_stop_set;
-static sigset_t thread_print_set;
struct thread_db_info
{
/* List of known processes using thread_db, and the required
bookkeeping. */
-struct thread_db_info *thread_db_list;
+static thread_db_info *thread_db_list;
static void thread_db_find_new_threads_1 (thread_info *stopped);
static void thread_db_find_new_threads_2 (thread_info *stopped,
if (version_msym.minsym == NULL)
return 0;
- version_addr = BMSYMBOL_VALUE_ADDRESS (version_msym);
+ version_addr = version_msym.value_address ();
gdb::unique_xmalloc_ptr<char> version
= target_read_string (version_addr, 32, &got);
if (version != nullptr
calls are made, we just assume they were; future changes
to how GDB accesses TLS could result in this passing
without exercising the calls it's supposed to. */
- ptid_t ptid = ptid_t (tdb_testinfo->info->pid, ti.ti_lid, 0);
+ ptid_t ptid = ptid_t (tdb_testinfo->info->pid, ti.ti_lid);
thread_info *thread_info = find_thread_ptid (linux_target, ptid);
if (thread_info != NULL && thread_info->priv != NULL)
{
catch (const gdb_exception_error &except)
{
if (warning_pre_print)
- fputs_unfiltered (warning_pre_print, gdb_stderr);
+ gdb_puts (warning_pre_print, gdb_stderr);
exception_fprintf (gdb_stderr, except,
_("libthread_db integrity checks failed: "));
return test_passed;
}
+/* Predicate which tests whether objfile OBJ refers to the library
+ containing pthread related symbols. Historically, this library has
+ been named in such a way that looking for "libpthread" in the name
+ was sufficient to identify it. As of glibc-2.34, the C library
+ (libc) contains the thread library symbols. Therefore we check
+ that the name matches a possible thread library, but we also check
+ that it contains at least one of the symbols (pthread_create) that
+ we'd expect to find in the thread library. */
+
+static bool
+libpthread_objfile_p (objfile *obj)
+{
+ return (libpthread_name_p (objfile_name (obj))
+ && lookup_minimal_symbol ("pthread_create",
+ NULL,
+ obj).minsym != NULL);
+}
+
/* Attempt to initialize dlopen()ed libthread_db, described by INFO.
Return true on success.
Failure could happen if libthread_db does not have symbols we expect,
if (err != TD_OK)
{
if (libthread_db_debug)
- fprintf_unfiltered (gdb_stdlog, _("td_ta_new failed: %s\n"),
- thread_db_err_str (err));
+ gdb_printf (gdb_stdlog, _("td_ta_new failed: %s\n"),
+ thread_db_err_str (err));
else
switch (err)
{
if (info->td_ta_thr_iter_p == NULL)
{
- struct lwp_info *lp;
int pid = inferior_ptid.pid ();
thread_info *curr_thread = inferior_thread ();
linux_stop_and_wait_all_lwps ();
- ALL_LWPS (lp)
+ for (const lwp_info *lp : all_lwps ())
if (lp->ptid.pid () == pid)
thread_from_lwp (curr_thread, lp->ptid);
return false;
}
- printf_unfiltered (_("[Thread debugging using libthread_db enabled]\n"));
+ gdb_printf (_("[Thread debugging using libthread_db enabled]\n"));
- if (*libthread_db_search_path || libthread_db_debug)
+ if (!libthread_db_search_path.empty () || libthread_db_debug)
{
- struct ui_file *file;
const char *library;
library = dladdr_to_soname ((const void *) *info->td_ta_new_p);
if (library == NULL)
library = LIBTHREAD_DB_SO;
- /* If we'd print this to gdb_stdout when debug output is
- disabled, still print it to gdb_stdout if debug output is
- enabled. User visible output should not depend on debug
- settings. */
- file = *libthread_db_search_path != '\0' ? gdb_stdout : gdb_stdlog;
- fprintf_unfiltered (file,
- _("Using host libthread_db library \"%ps\".\n"),
- styled_string (file_name_style.style (), library));
+ gdb_printf (_("Using host libthread_db library \"%ps\".\n"),
+ styled_string (file_name_style.style (), library));
}
/* The thread library was detected. Activate the thread_db target
for this process. */
- push_target (&the_thread_db_target);
+ current_inferior ()->push_target (&the_thread_db_target);
return true;
}
struct thread_db_info *info;
if (libthread_db_debug)
- fprintf_unfiltered (gdb_stdlog,
- _("Trying host libthread_db library: %s.\n"),
- library);
+ gdb_printf (gdb_stdlog,
+ _("Trying host libthread_db library: %s.\n"),
+ library);
if (check_auto_load_safe)
{
/* Do not print warnings by file_is_auto_load_safe if the library does
not exist at this place. */
if (libthread_db_debug)
- fprintf_unfiltered (gdb_stdlog, _("open failed: %s.\n"),
- safe_strerror (errno));
+ gdb_printf (gdb_stdlog, _("open failed: %s.\n"),
+ safe_strerror (errno));
return false;
}
- if (!file_is_auto_load_safe (library, _("auto-load: Loading libthread-db "
- "library \"%s\" from explicit "
- "directory.\n"),
- library))
+ auto_load_debug_printf
+ ("Loading libthread-db library \"%s\" from explicit directory.",
+ library);
+
+ if (!file_is_auto_load_safe (library))
return false;
}
if (handle == NULL)
{
if (libthread_db_debug)
- fprintf_unfiltered (gdb_stdlog, _("dlopen failed: %s.\n"), dlerror ());
+ gdb_printf (gdb_stdlog, _("dlopen failed: %s.\n"), dlerror ());
return false;
}
const char *const libpath = dladdr_to_soname (td_init);
if (libpath != NULL)
- fprintf_unfiltered (gdb_stdlog, _("Host %s resolved to: %s.\n"),
- library, libpath);
+ gdb_printf (gdb_stdlog, _("Host %s resolved to: %s.\n"),
+ library, libpath);
}
}
if (strchr (library, '/') != NULL)
info->filename = gdb_realpath (library).release ();
- if (try_thread_db_load_1 (info))
- return true;
+ try
+ {
+ if (try_thread_db_load_1 (info))
+ return true;
+ }
+ catch (const gdb_exception_error &except)
+ {
+ if (libthread_db_debug)
+ exception_fprintf (gdb_stdlog, except,
+ "Warning: While trying to load libthread_db: ");
+ }
/* This library "refused" to work on current inferior. */
delete_thread_db_info (current_inferior ()->process_target (),
return false;
for (objfile *obj : current_program_space->objfiles ())
- if (libpthread_name_p (objfile_name (obj)))
+ if (libpthread_objfile_p (obj))
{
if (try_thread_db_load_from_pdir_1 (obj, subdir))
return true;
bool rc = false;
std::vector<gdb::unique_xmalloc_ptr<char>> dir_vec
- = dirnames_to_char_ptr_vec (libthread_db_search_path);
+ = dirnames_to_char_ptr_vec (libthread_db_search_path.c_str ());
for (const gdb::unique_xmalloc_ptr<char> &this_dir_up : dir_vec)
{
}
if (libthread_db_debug)
- fprintf_unfiltered (gdb_stdlog,
- _("thread_db_load_search returning %d\n"), rc);
+ gdb_printf (gdb_stdlog,
+ _("thread_db_load_search returning %d\n"), rc);
return rc;
}
has_libpthread (void)
{
for (objfile *obj : current_program_space->objfiles ())
- if (libpthread_name_p (objfile_name (obj)))
+ if (libpthread_objfile_p (obj))
return true;
return false;
static bool
thread_db_load (void)
{
- struct thread_db_info *info;
+ inferior *inf = current_inferior ();
- info = get_thread_db_info (current_inferior ()->process_target (),
- inferior_ptid.pid ());
+ /* When attaching / handling fork child, don't try loading libthread_db
+ until we know about all shared libraries. */
+ if (inf->in_initial_library_scan)
+ return false;
+
+ thread_db_info *info = get_thread_db_info (inf->process_target (),
+ inferior_ptid.pid ());
if (info != NULL)
return true;
{
if (!thread_signals)
{
- sigset_t mask;
int i;
- lin_thread_get_thread_signals (&mask);
- sigemptyset (&thread_stop_set);
- sigemptyset (&thread_print_set);
-
- for (i = 1; i < NSIG; i++)
+ for (i = 0; i < lin_thread_get_thread_signal_num (); i++)
{
- if (sigismember (&mask, i))
- {
- if (signal_stop_update (gdb_signal_from_host (i), 0))
- sigaddset (&thread_stop_set, i);
- if (signal_print_update (gdb_signal_from_host (i), 0))
- sigaddset (&thread_print_set, i);
- thread_signals = 1;
- }
+ int sig = lin_thread_get_thread_signal (i);
+ signal_stop_update (gdb_signal_from_host (sig), 0);
+ signal_print_update (gdb_signal_from_host (sig), 0);
+ thread_signals = 1;
}
}
}
an inferior is created (or otherwise acquired, e.g. attached to)
and when new shared libraries are loaded into a running process. */
-void
+static void
check_for_thread_db (void)
{
/* Do nothing if we couldn't load libthread_db.so.1. */
of the list of shared libraries to load, and in an app of several
thousand shared libraries, this can otherwise be painful. */
&& ((objfile->flags & OBJF_MAINLINE) != 0
- || libpthread_name_p (objfile_name (objfile))))
+ || libpthread_objfile_p (objfile)))
check_for_thread_db ();
}
/* NOTE: From this point on, inferior_ptid is null_ptid. */
/* Detach the thread_db target from this inferior. */
- unpush_target (this);
+ inf->unpush_target (this);
}
ptid_t
ptid = beneath->wait (ptid, ourstatus, options);
- switch (ourstatus->kind)
+ switch (ourstatus->kind ())
{
case TARGET_WAITKIND_IGNORE:
case TARGET_WAITKIND_EXITED:
case TARGET_WAITKIND_THREAD_EXITED:
case TARGET_WAITKIND_SIGNALLED:
+ case TARGET_WAITKIND_EXECD:
return ptid;
}
if (info == NULL)
return ptid;
- if (ourstatus->kind == TARGET_WAITKIND_EXECD)
- {
- /* New image, it may or may not end up using thread_db. Assume
- not unless we find otherwise. */
- delete_thread_db_info (beneath, ptid.pid ());
- unpush_target (this);
-
- return ptid;
- }
-
/* Fill in the thread's user-level thread id and status. */
thread_from_lwp (find_thread_ptid (beneath, ptid), ptid);
target_beneath->mourn_inferior ();
/* Detach the thread_db target from this inferior. */
- unpush_target (this);
+ current_inferior ()->unpush_target (this);
+}
+
+void
+thread_db_target::follow_exec (inferior *follow_inf, ptid_t ptid,
+ const char *execd_pathname)
+{
+ process_stratum_target *beneath
+ = as_process_stratum_target (this->beneath ());
+
+ delete_thread_db_info (beneath, ptid.pid ());
+
+ current_inferior ()->unpush_target (this);
+ beneath->follow_exec (follow_inf, ptid, execd_pathname);
}
struct callback_data
terminated and joined threads with kernel thread ID -1. See
glibc PR17707. */
if (libthread_db_debug)
- fprintf_unfiltered (gdb_stdlog,
- "thread_db: skipping exited and "
- "joined thread (0x%lx)\n",
- (unsigned long) ti.ti_tid);
+ gdb_printf (gdb_stdlog,
+ "thread_db: skipping exited and "
+ "joined thread (0x%lx)\n",
+ (unsigned long) ti.ti_tid);
return 0;
}
if (libthread_db_debug)
{
- fprintf_unfiltered (gdb_stdlog,
- _("Found %d new threads in iteration %d.\n"),
- data.new_threads, iteration);
+ gdb_printf (gdb_stdlog,
+ _("Found %d new threads in iteration %d.\n"),
+ data.new_threads, iteration);
}
if (errp != NULL)
continue;
thread_info *thread = any_live_thread_of_inferior (inf);
- if (thread == NULL || thread->executing)
+ if (thread == NULL || thread->executing ())
continue;
/* It's best to avoid td_ta_thr_iter if possible. That walks
/* Implement the to_get_ada_task_ptid target method for this target. */
ptid_t
-thread_db_target::get_ada_task_ptid (long lwp, long thread)
+thread_db_target::get_ada_task_ptid (long lwp, ULONGEST thread)
{
/* NPTL uses a 1:1 model, so the LWP id suffices. */
- return ptid_t (inferior_ptid.pid (), lwp, 0);
+ return ptid_t (inferior_ptid.pid (), lwp);
}
void
ui_out_emit_tuple tuple_emitter (uiout, NULL);
info = array[i];
- uiout->field_string ("filename", info->filename);
+ uiout->field_string ("filename", info->filename,
+ file_name_style.style ());
std::string pids;
while (i < array.size () && strcmp (info->filename,
i++;
}
- uiout->field_string ("pids", pids.c_str ());
+ uiout->field_string ("pids", pids);
uiout->text ("\n");
}
and until there is a running inferior, we can't tell which
libthread_db is the correct one to load. */
- libthread_db_search_path = xstrdup (LIBTHREAD_DB_SEARCH_PATH);
-
add_setshow_optional_filename_cmd ("libthread-db-search-path",
class_support,
&libthread_db_search_path, _("\
&maintenance_show_cmdlist);
/* Add ourselves to objfile event chain. */
- gdb::observers::new_objfile.attach (thread_db_new_objfile);
+ gdb::observers::new_objfile.attach (thread_db_new_objfile, "linux-thread-db");
/* Add ourselves to inferior_created event chain.
This is needed to handle debugging statically linked programs where
the new_objfile observer won't get called for libpthread. */
- gdb::observers::inferior_created.attach (thread_db_inferior_created);
+ gdb::observers::inferior_created.attach (thread_db_inferior_created,
+ "linux-thread-db");
}