|  | /* Program and address space management, for GDB, the GNU debugger. | 
|  |  | 
|  | Copyright (C) 2009-2025 Free Software Foundation, Inc. | 
|  |  | 
|  | This file is part of GDB. | 
|  |  | 
|  | 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 "cli/cli-cmds.h" | 
|  | #include "objfiles.h" | 
|  | #include "gdbcore.h" | 
|  | #include "solib.h" | 
|  | #include "gdbthread.h" | 
|  | #include "inferior.h" | 
|  | #include <algorithm> | 
|  | #include "cli/cli-style.h" | 
|  | #include "observable.h" | 
|  |  | 
|  | /* The last program space number assigned.  */ | 
|  | static int last_program_space_num = 0; | 
|  |  | 
|  | /* The head of the program spaces list.  */ | 
|  | std::vector<struct program_space *> program_spaces; | 
|  |  | 
|  | /* Pointer to the current program space.  */ | 
|  | struct program_space *current_program_space; | 
|  |  | 
|  | /* The last address space number assigned.  */ | 
|  | static int highest_address_space_num; | 
|  |  | 
|  |  | 
|  |  | 
|  | /* Create a new address space object, and add it to the list.  */ | 
|  |  | 
|  | address_space::address_space () | 
|  | : m_num (++highest_address_space_num) | 
|  | { | 
|  | } | 
|  |  | 
|  | /* Maybe create a new address space object, and add it to the list, or | 
|  | return a pointer to an existing address space, in case inferiors | 
|  | share an address space on this target system.  */ | 
|  |  | 
|  | address_space_ref_ptr | 
|  | maybe_new_address_space () | 
|  | { | 
|  | int shared_aspace | 
|  | = gdbarch_has_shared_address_space (current_inferior ()->arch ()); | 
|  |  | 
|  | if (shared_aspace) | 
|  | { | 
|  | /* Just return the first in the list.  */ | 
|  | return program_spaces[0]->aspace; | 
|  | } | 
|  |  | 
|  | return new_address_space (); | 
|  | } | 
|  |  | 
|  | /* Start counting over from scratch.  */ | 
|  |  | 
|  | static void | 
|  | init_address_spaces (void) | 
|  | { | 
|  | highest_address_space_num = 0; | 
|  | } | 
|  |  | 
|  |  | 
|  |  | 
|  | /* Remove a program space from the program spaces list.  */ | 
|  |  | 
|  | static void | 
|  | remove_program_space (program_space *pspace) | 
|  | { | 
|  | gdb_assert (pspace != NULL); | 
|  |  | 
|  | auto iter = std::find (program_spaces.begin (), program_spaces.end (), | 
|  | pspace); | 
|  | gdb_assert (iter != program_spaces.end ()); | 
|  | program_spaces.erase (iter); | 
|  | } | 
|  |  | 
|  | /* See progspace.h.  */ | 
|  |  | 
|  | program_space::program_space (address_space_ref_ptr aspace_) | 
|  | : num (++last_program_space_num), | 
|  | aspace (std::move (aspace_)) | 
|  | { | 
|  | program_spaces.push_back (this); | 
|  | gdb::observers::new_program_space.notify (this); | 
|  | } | 
|  |  | 
|  | /* See progspace.h.  */ | 
|  |  | 
|  | program_space::~program_space () | 
|  | { | 
|  | gdb_assert (this != current_program_space); | 
|  |  | 
|  | gdb::observers::free_program_space.notify (this); | 
|  | remove_program_space (this); | 
|  |  | 
|  | scoped_restore_current_program_space restore_pspace; | 
|  |  | 
|  | set_current_program_space (this); | 
|  |  | 
|  | breakpoint_program_space_exit (this); | 
|  | no_shared_libraries (this); | 
|  | free_all_objfiles (); | 
|  | /* Defer breakpoint re-set because we don't want to create new | 
|  | locations for this pspace which we're tearing down.  */ | 
|  | clear_symtab_users (SYMFILE_DEFER_BP_RESET); | 
|  | } | 
|  |  | 
|  | /* See progspace.h.  */ | 
|  |  | 
|  | bool | 
|  | program_space::multi_objfile_p () const | 
|  | { | 
|  | return (!m_objfiles_list.empty () | 
|  | && std::next (m_objfiles_list.begin ()) != m_objfiles_list.end ()); | 
|  | } | 
|  |  | 
|  | /* See progspace.h.  */ | 
|  |  | 
|  | void | 
|  | program_space::free_all_objfiles () | 
|  | { | 
|  | /* Any objfile reference would become stale.  */ | 
|  | for (const solib &so : this->solibs ()) | 
|  | gdb_assert (so.objfile == NULL); | 
|  |  | 
|  | while (!m_objfiles_list.empty ()) | 
|  | this->remove_objfile (&m_objfiles_list.front ()); | 
|  | } | 
|  |  | 
|  | /* See progspace.h.  */ | 
|  |  | 
|  | void | 
|  | program_space::iterate_over_objfiles_in_search_order | 
|  | (iterate_over_objfiles_in_search_order_cb_ftype cb, objfile *current_objfile) | 
|  | { | 
|  | if (m_solib_ops != nullptr) | 
|  | return m_solib_ops->iterate_over_objfiles_in_search_order | 
|  | (cb, current_objfile); | 
|  |  | 
|  | for (const auto objfile : this->objfiles ()) | 
|  | if (cb (objfile)) | 
|  | return; | 
|  | } | 
|  |  | 
|  | /* See progspace.h.  */ | 
|  |  | 
|  | void | 
|  | program_space::add_objfile (std::unique_ptr<objfile> &&objfile, | 
|  | struct objfile *before) | 
|  | { | 
|  | if (before == nullptr) | 
|  | m_objfiles_list.push_back (std::move (objfile)); | 
|  | else | 
|  | { | 
|  | gdb_assert (before->is_linked ()); | 
|  | m_objfiles_list.insert (m_objfiles_list.iterator_to (*before), | 
|  | std::move (objfile)); | 
|  | } | 
|  | } | 
|  |  | 
|  | /* See progspace.h.  */ | 
|  |  | 
|  | void | 
|  | program_space::remove_objfile (struct objfile *objfile) | 
|  | { | 
|  | /* Removing an objfile from the objfile list invalidates any frame | 
|  | that was built using frame info found in the objfile.  Reinit the | 
|  | frame cache to get rid of any frame that might otherwise | 
|  | reference stale info.  */ | 
|  | reinit_frame_cache (); | 
|  |  | 
|  | if (objfile == symfile_object_file) | 
|  | symfile_object_file = NULL; | 
|  |  | 
|  | gdb_assert (objfile->is_linked ()); | 
|  | m_objfiles_list.erase (m_objfiles_list.iterator_to (*objfile)); | 
|  | } | 
|  |  | 
|  | /* See progspace.h.  */ | 
|  |  | 
|  | struct objfile * | 
|  | program_space::objfile_for_address (CORE_ADDR address) | 
|  | { | 
|  | for (auto iter : objfiles ()) | 
|  | { | 
|  | /* Don't check separate debug objfiles.  */ | 
|  | if (iter->separate_debug_objfile_backlink != nullptr) | 
|  | continue; | 
|  | if (is_addr_in_objfile (address, iter)) | 
|  | return iter; | 
|  | } | 
|  | return nullptr; | 
|  | } | 
|  |  | 
|  | /* See progspace.h.  */ | 
|  |  | 
|  | void | 
|  | program_space::exec_close () | 
|  | { | 
|  | if (ebfd != nullptr) | 
|  | { | 
|  | /* Removing target sections may close the exec_ops target. | 
|  | Clear ebfd before doing so to prevent recursion.  We | 
|  | move it to another ref_ptr instead of saving it to a raw | 
|  | pointer to avoid it looking like possible use-after-free.  */ | 
|  | gdb_bfd_ref_ptr saved_ebfd = std::move (ebfd); | 
|  | ebfd.reset (nullptr); | 
|  | ebfd_mtime = 0; | 
|  |  | 
|  | remove_target_sections (saved_ebfd.get ()); | 
|  |  | 
|  | m_exec_filename.reset (); | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Copies program space SRC to DEST.  Copies the main executable file, | 
|  | and the main symbol file.  Returns DEST.  */ | 
|  |  | 
|  | struct program_space * | 
|  | clone_program_space (struct program_space *dest, struct program_space *src) | 
|  | { | 
|  | scoped_restore_current_program_space restore_pspace; | 
|  |  | 
|  | set_current_program_space (dest); | 
|  |  | 
|  | if (src->exec_filename () != nullptr) | 
|  | exec_file_attach (src->exec_filename (), 0); | 
|  |  | 
|  | if (src->symfile_object_file != NULL) | 
|  | symbol_file_add_main (objfile_name (src->symfile_object_file), | 
|  | SYMFILE_DEFER_BP_RESET); | 
|  |  | 
|  | return dest; | 
|  | } | 
|  |  | 
|  | /* Sets PSPACE as the current program space.  It is the caller's | 
|  | responsibility to make sure that the currently selected | 
|  | inferior/thread matches the selected program space.  */ | 
|  |  | 
|  | void | 
|  | set_current_program_space (struct program_space *pspace) | 
|  | { | 
|  | if (current_program_space == pspace) | 
|  | return; | 
|  |  | 
|  | gdb_assert (pspace != NULL); | 
|  |  | 
|  | current_program_space = pspace; | 
|  |  | 
|  | /* Different symbols change our view of the frame chain.  */ | 
|  | reinit_frame_cache (); | 
|  | } | 
|  |  | 
|  | /* Returns true iff there's no inferior bound to PSPACE.  */ | 
|  |  | 
|  | bool | 
|  | program_space::empty () | 
|  | { | 
|  | return find_inferior_for_program_space (this) == nullptr; | 
|  | } | 
|  |  | 
|  | /* Prints the list of program spaces and their details on UIOUT.  If | 
|  | REQUESTED is not -1, it's the ID of the pspace that should be | 
|  | printed.  Otherwise, all spaces are printed.  */ | 
|  |  | 
|  | static void | 
|  | print_program_space (struct ui_out *uiout, int requested) | 
|  | { | 
|  | int count = 0; | 
|  |  | 
|  | /* Start with a minimum width of 17 for the executable name column.  */ | 
|  | size_t longest_exec_name = 17; | 
|  |  | 
|  | /* Compute number of pspaces we will print.  */ | 
|  | for (struct program_space *pspace : program_spaces) | 
|  | { | 
|  | if (requested != -1 && pspace->num != requested) | 
|  | continue; | 
|  |  | 
|  | if (pspace->exec_filename () != nullptr) | 
|  | longest_exec_name = std::max (strlen (pspace->exec_filename ()), | 
|  | longest_exec_name); | 
|  |  | 
|  | ++count; | 
|  | } | 
|  |  | 
|  | /* There should always be at least one.  */ | 
|  | gdb_assert (count > 0); | 
|  |  | 
|  | ui_out_emit_table table_emitter (uiout, 3, count, "pspaces"); | 
|  | uiout->table_header (1, ui_left, "current", ""); | 
|  | uiout->table_header (4, ui_left, "id", "Id"); | 
|  | uiout->table_header (longest_exec_name, ui_left, "exec", "Executable"); | 
|  | uiout->table_body (); | 
|  |  | 
|  | for (struct program_space *pspace : program_spaces) | 
|  | { | 
|  | int printed_header; | 
|  |  | 
|  | if (requested != -1 && requested != pspace->num) | 
|  | continue; | 
|  |  | 
|  | ui_out_emit_tuple tuple_emitter (uiout, NULL); | 
|  |  | 
|  | if (pspace == current_program_space) | 
|  | uiout->field_string ("current", "*"); | 
|  | else | 
|  | uiout->field_skip ("current"); | 
|  |  | 
|  | uiout->field_signed ("id", pspace->num); | 
|  |  | 
|  | if (pspace->exec_filename () != nullptr) | 
|  | uiout->field_string ("exec", pspace->exec_filename (), | 
|  | file_name_style.style ()); | 
|  | else | 
|  | uiout->field_skip ("exec"); | 
|  |  | 
|  | /* Print extra info that doesn't really fit in tabular form. | 
|  | Currently, we print the list of inferiors bound to a pspace. | 
|  | There can be more than one inferior bound to the same pspace, | 
|  | e.g., both parent/child inferiors in a vfork, or, on targets | 
|  | that share pspaces between inferiors.  */ | 
|  | printed_header = 0; | 
|  |  | 
|  | /* We're going to switch inferiors.  */ | 
|  | scoped_restore_current_thread restore_thread; | 
|  |  | 
|  | for (inferior *inf : all_inferiors ()) | 
|  | if (inf->pspace == pspace) | 
|  | { | 
|  | /* Switch to inferior in order to call target methods.  */ | 
|  | switch_to_inferior_no_thread (inf); | 
|  |  | 
|  | if (!printed_header) | 
|  | { | 
|  | printed_header = 1; | 
|  | gdb_printf ("\n\tBound inferiors: ID %d (%s)", | 
|  | inf->num, | 
|  | target_pid_to_str (ptid_t (inf->pid)).c_str ()); | 
|  | } | 
|  | else | 
|  | gdb_printf (", ID %d (%s)", | 
|  | inf->num, | 
|  | target_pid_to_str (ptid_t (inf->pid)).c_str ()); | 
|  | } | 
|  |  | 
|  | uiout->text ("\n"); | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Boolean test for an already-known program space id.  */ | 
|  |  | 
|  | static int | 
|  | valid_program_space_id (int num) | 
|  | { | 
|  | for (struct program_space *pspace : program_spaces) | 
|  | if (pspace->num == num) | 
|  | return 1; | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /* If ARGS is NULL or empty, print information about all program | 
|  | spaces.  Otherwise, ARGS is a text representation of a LONG | 
|  | indicating which the program space to print information about.  */ | 
|  |  | 
|  | static void | 
|  | maintenance_info_program_spaces_command (const char *args, int from_tty) | 
|  | { | 
|  | int requested = -1; | 
|  |  | 
|  | if (args && *args) | 
|  | { | 
|  | requested = parse_and_eval_long (args); | 
|  | if (!valid_program_space_id (requested)) | 
|  | error (_("program space ID %d not known."), requested); | 
|  | } | 
|  |  | 
|  | print_program_space (current_uiout, requested); | 
|  | } | 
|  |  | 
|  | /* Update all program spaces matching to address spaces.  The user may | 
|  | have created several program spaces, and loaded executables into | 
|  | them before connecting to the target interface that will create the | 
|  | inferiors.  All that happens before GDB has a chance to know if the | 
|  | inferiors will share an address space or not.  Call this after | 
|  | having connected to the target interface and having fetched the | 
|  | target description, to fixup the program/address spaces mappings. | 
|  |  | 
|  | It is assumed that there are no bound inferiors yet, otherwise, | 
|  | they'd be left with stale referenced to released aspaces.  */ | 
|  |  | 
|  | void | 
|  | update_address_spaces (void) | 
|  | { | 
|  | int shared_aspace | 
|  | = gdbarch_has_shared_address_space (current_inferior ()->arch ()); | 
|  |  | 
|  | init_address_spaces (); | 
|  |  | 
|  | if (shared_aspace) | 
|  | { | 
|  | address_space_ref_ptr aspace = new_address_space (); | 
|  |  | 
|  | for (struct program_space *pspace : program_spaces) | 
|  | pspace->aspace = aspace; | 
|  | } | 
|  | else | 
|  | for (struct program_space *pspace : program_spaces) | 
|  | pspace->aspace = new_address_space (); | 
|  |  | 
|  | for (inferior *inf : all_inferiors ()) | 
|  | if (gdbarch_has_global_solist (current_inferior ()->arch ())) | 
|  | inf->aspace = maybe_new_address_space (); | 
|  | else | 
|  | inf->aspace = inf->pspace->aspace; | 
|  | } | 
|  |  | 
|  |  | 
|  |  | 
|  | /* See progspace.h.  */ | 
|  |  | 
|  | void | 
|  | program_space::clear_solib_cache () | 
|  | { | 
|  | added_solibs.clear (); | 
|  | deleted_solibs.clear (); | 
|  | } | 
|  |  | 
|  | /* See progspace.h.  */ | 
|  |  | 
|  | void | 
|  | initialize_progspace () | 
|  | { | 
|  | add_cmd ("program-spaces", class_maintenance, | 
|  | maintenance_info_program_spaces_command, | 
|  | _("Info about currently known program spaces."), | 
|  | &maintenanceinfolist); | 
|  |  | 
|  | /* There's always one program space.  Note that this function isn't | 
|  | an automatic _initialize_foo function, since other | 
|  | _initialize_foo routines may need to install their per-pspace | 
|  | data keys.  We can only allocate a progspace when all those | 
|  | modules have done that.  Do this before | 
|  | initialize_current_architecture, because that accesses the ebfd | 
|  | of current_program_space.  */ | 
|  | current_program_space = new program_space (new_address_space ()); | 
|  | } |