+ if (i)
+ pids_len -= strlen (", ");
+
+ /* Table header shifted right by preceding "libthread-db: " would not match
+ its columns. */
+ if (array.size () > 0 && args == auto_load_info_scripts_pattern_nl)
+ uiout->text ("\n");
+
+ {
+ ui_out_emit_table table_emitter (uiout, 2, unique_filenames,
+ "LinuxThreadDbTable");
+
+ uiout->table_header (max_filename_len, ui_left, "filename", "Filename");
+ uiout->table_header (pids_len, ui_left, "PIDs", "Pids");
+ uiout->table_body ();
+
+ /* Note I is incremented inside the cycle, not at its end. */
+ for (i = 0; i < array.size ();)
+ {
+ ui_out_emit_tuple tuple_emitter (uiout, NULL);
+
+ info = array[i];
+ uiout->field_string ("filename", info->filename);
+
+ std::string pids;
+ while (i < array.size () && strcmp (info->filename,
+ array[i]->filename) == 0)
+ {
+ if (!pids.empty ())
+ pids += ", ";
+ string_appendf (pids, "%u", array[i]->pid);
+ i++;
+ }
+
+ uiout->field_string ("pids", pids.c_str ());
+
+ uiout->text ("\n");
+ }
+ }
+
+ if (array.empty ())
+ uiout->message (_("No auto-loaded libthread-db.\n"));
+}
+
+/* Implement 'maintenance check libthread-db'. */
+
+static void
+maintenance_check_libthread_db (const char *args, int from_tty)
+{
+ int inferior_pid = inferior_ptid.pid ();
+ struct thread_db_info *info;
+
+ if (inferior_pid == 0)
+ error (_("No inferior running"));
+
+ info = get_thread_db_info (current_inferior ()->process_target (),
+ inferior_pid);
+ if (info == NULL)
+ error (_("No libthread_db loaded"));
+
+ check_thread_db (info, true);
+}
+
+void _initialize_thread_db ();
+void
+_initialize_thread_db ()
+{
+ /* Defer loading of libthread_db.so until inferior is running.
+ This allows gdb to load correct libthread_db for a given
+ executable -- there could be multiple versions of glibc,
+ 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, _("\
+Set search path for libthread_db."), _("\
+Show the current search path or libthread_db."), _("\
+This path is used to search for libthread_db to be loaded into \
+gdb itself.\n\
+Its value is a colon (':') separate list of directories to search.\n\
+Setting the search path to an empty list resets it to its default value."),
+ set_libthread_db_search_path,
+ NULL,
+ &setlist, &showlist);
+
+ add_setshow_zuinteger_cmd ("libthread-db", class_maintenance,
+ &libthread_db_debug, _("\
+Set libthread-db debugging."), _("\
+Show libthread-db debugging."), _("\
+When non-zero, libthread-db debugging is enabled."),
+ NULL,
+ show_libthread_db_debug,
+ &setdebuglist, &showdebuglist);
+
+ add_setshow_boolean_cmd ("libthread-db", class_support,
+ &auto_load_thread_db, _("\
+Enable or disable auto-loading of inferior specific libthread_db."), _("\
+Show whether auto-loading inferior specific libthread_db is enabled."), _("\
+If enabled, libthread_db will be searched in 'set libthread-db-search-path'\n\
+locations to load libthread_db compatible with the inferior.\n\
+Standard system libthread_db still gets loaded even with this option off.\n\
+This option has security implications for untrusted inferiors."),
+ NULL, show_auto_load_thread_db,
+ auto_load_set_cmdlist_get (),
+ auto_load_show_cmdlist_get ());
+
+ add_cmd ("libthread-db", class_info, info_auto_load_libthread_db,
+ _("Print the list of loaded inferior specific libthread_db.\n\
+Usage: info auto-load libthread-db"),
+ auto_load_info_cmdlist_get ());
+
+ add_cmd ("libthread-db", class_maintenance,
+ maintenance_check_libthread_db, _("\
+Run integrity checks on the current inferior's libthread_db."),
+ &maintenancechecklist);
+
+ add_setshow_boolean_cmd ("check-libthread-db",
+ class_maintenance,
+ &check_thread_db_on_load, _("\
+Set whether to check libthread_db at load time."), _("\
+Show whether to check libthread_db at load time."), _("\
+If enabled GDB will run integrity checks on inferior specific libthread_db\n\
+as they are loaded."),
+ NULL,
+ NULL,
+ &maintenance_set_cmdlist,
+ &maintenance_show_cmdlist);
+
+ /* Add ourselves to objfile event chain. */
+ gdb::observers::new_objfile.attach (thread_db_new_objfile);
+
+ /* 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);