diff --git a/gdb/infcmd.c b/gdb/infcmd.c index bd5dbb02f48..8f7f5eecc66 100644 --- a/gdb/infcmd.c +++ b/gdb/infcmd.c @@ -366,7 +366,7 @@ strip_bg_char (const char *args, int *bg_char_p) /* See inferior.h. */ void -post_create_inferior (int from_tty, bool set_pspace_solib_ops) +post_create_inferior (int from_tty, bool push_arch_solib_ops) { /* Be sure we own the terminal in case write operations are performed. */ target_terminal::ours_for_output (); @@ -397,10 +397,16 @@ post_create_inferior (int from_tty, bool set_pspace_solib_ops) throw; } - if (set_pspace_solib_ops) - current_program_space->set_solib_ops - (gdbarch_make_solib_ops (current_inferior ()->arch (), - current_program_space)); + if (push_arch_solib_ops) + { + /* This is called when an inferior gains execution. Any solib_ops + from previous executions should have been cleared by + target_pre_inferior. */ + gdb_assert (current_program_space->solib_ops ().empty ()); + current_program_space->add_solib_ops + (gdbarch_make_solib_ops (current_inferior ()->arch (), + current_program_space)); + } { const unsigned solib_add_generation diff --git a/gdb/inferior.h b/gdb/inferior.h index 9c031035a23..19c5da76ca5 100644 --- a/gdb/inferior.h +++ b/gdb/inferior.h @@ -216,10 +216,10 @@ extern void setup_inferior (int from_tty); means (running, attaching, connecting, et cetera). The target should be stopped. - If SET_PSPACE_SOLIB_OPS is true, initialize the program space's solib - provider using the current inferior's architecture. */ + If PUSH_ARCH_SOLIB_OPS is true, add an solib_ops to the current inferior's + program space provider using the current inferior's architecture. */ -extern void post_create_inferior (int from_tty, bool set_pspace_solib_ops); +extern void post_create_inferior (int from_tty, bool push_arch_solib_ops); extern void attach_command (const char *, int); diff --git a/gdb/infrun.c b/gdb/infrun.c index ab3fde11cf9..5372bc8e53c 100644 --- a/gdb/infrun.c +++ b/gdb/infrun.c @@ -1378,7 +1378,7 @@ follow_exec (ptid_t ptid, const char *exec_file_target) we don't want those to be satisfied by the libraries of the previous incarnation of this process. */ no_shared_libraries (current_program_space); - current_program_space->unset_solib_ops (); + current_program_space->clear_solib_ops (); inferior *execing_inferior = current_inferior (); inferior *following_inferior; @@ -1435,7 +1435,7 @@ follow_exec (ptid_t ptid, const char *exec_file_target) registers. */ target_find_description (); - following_inferior->pspace->set_solib_ops + following_inferior->pspace->add_solib_ops (gdbarch_make_solib_ops (following_inferior->arch (), following_inferior->pspace)); gdb::observers::inferior_execd.notify (execing_inferior, following_inferior); diff --git a/gdb/progspace.c b/gdb/progspace.c index 7023ccddc54..b513cfd6822 100644 --- a/gdb/progspace.c +++ b/gdb/progspace.c @@ -98,6 +98,42 @@ program_space::~program_space () /* See progspace.h. */ +void +program_space::clear_solib_ops () +{ + while (!m_solib_ops.empty ()) + this->remove_solib_ops (*m_solib_ops.front ()); +} + +/* See progspace.h. */ + +void +program_space::remove_solib_ops (const struct solib_ops &ops) +{ + auto ops_it + = std::find_if (m_solib_ops.begin (), m_solib_ops.end (), + [&ops] (const auto &up) { return up.get () == &ops; }); + + gdb_assert (ops_it != m_solib_ops.end ()); + + /* Remove all solibs provided by the solib_ops being removed. */ + for (auto solibs_it = m_solib_list.begin (); + solibs_it != m_solib_list.end ();) + { + if (&solibs_it->ops () != &ops) + { + ++solibs_it; + continue; + } + + solibs_it = remove_solib (this, solibs_it); + } + + m_solib_ops.erase (ops_it); +} + +/* See progspace.h. */ + bool program_space::multi_objfile_p () const { @@ -124,16 +160,58 @@ 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); + struct solib_ops *curr_ops = nullptr; - if (current_objfile != nullptr && cb (current_objfile)) - return; + if (current_objfile != nullptr) + { + if (!current_objfile->solibs ().empty ()) + { + /* If that objfile was created by an solib_ops, give a chance to that + solib_ops to iterate the relevant objfiles first. + If the objfile is associated to multiple struct solib, assume that + they are all from the same solib_ops (so, get the ops from the + first solib). */ + curr_ops = ¤t_objfile->solibs ().front ()->ops (); + + if (curr_ops->iterate_over_objfiles_in_search_order (cb, + current_objfile)) + return; + } + else + { + /* Otherwise, search this objfile first. */ + if (cb (current_objfile)) + return; + } + } + + /* We didn't find what we were looking for based on the current objfile's + context, so expand the search. Ask the other solib_ops. */ + for (auto &solib_ops : this->solib_ops ()) + { + if (solib_ops.get () == curr_ops) + continue; + + if (solib_ops->iterate_over_objfiles_in_search_order (cb, nullptr)) + return; + } + + /* Finally, look in the orphan objfiles. */ for (auto &objfile : this->objfiles ()) - if (&objfile != current_objfile && cb (&objfile)) - return; + { + /* The current objfile (if any) was already handled above. */ + if (&objfile == current_objfile) + continue; + + /* If the obfile has any associated solibs, then it is not orphan, it has + been handled above. */ + if (!objfile.solibs ().empty ()) + continue; + + if (cb (&objfile)) + return; + } } /* See progspace.h. */ diff --git a/gdb/progspace.h b/gdb/progspace.h index 21977747cb9..a5ef3deb337 100644 --- a/gdb/progspace.h +++ b/gdb/progspace.h @@ -242,26 +242,51 @@ struct program_space is outside all objfiles in this progspace. */ struct objfile *objfile_for_address (CORE_ADDR address); - /* Set this program space's solib provider. + /* Add OPS as an solib provider for this program space. - The solib provider must be unset prior to calling this method. */ - void set_solib_ops (solib_ops_up ops) + There must not be another instance of SOLIB_OPS_TYPE in the solib_ops list + of this program space. + + Return a non-owning reference to the ops. */ + template + solib_ops_type &add_solib_ops (std::unique_ptr ops) { - gdb_assert (m_solib_ops == nullptr); - m_solib_ops = std::move (ops); + gdb_assert (this->find_solib_ops () == nullptr); + + auto &ret = *ops; + m_solib_ops.emplace_back (std::move (ops)); + return ret; }; - /* Unset and free this program space's solib provider. */ - void unset_solib_ops () - { m_solib_ops = nullptr; } + /* Clear the list of solib providers for this program space. - /* Unset and return this program space's solib provider. */ - solib_ops_up release_solib_ops () - { return std::move (m_solib_ops); } + Remove all solibs from the program space. */ + void clear_solib_ops (); - /* Get this program space's solib provider. */ - struct solib_ops *solib_ops () const - { return m_solib_ops.get (); } + /* Remove OPS from the list of solib_ops of this program space. + + OPS must be present in the solib_ops list. + + Remove all solibs created by OPS from the program space. */ + void remove_solib_ops (const solib_ops &ops); + + /* Return a view of the solib providers for this program space. */ + std::vector &solib_ops () + { return m_solib_ops; } + + /* Find an solib_ops instance of type SOLIB_OPS_TYPE. + + Return nullptr if not found. */ + template + solib_ops_type *find_solib_ops () + { + for (auto &ops : this->solib_ops ()) + if (auto ret = dynamic_cast (ops.get ()); + ret != nullptr) + return ret; + + return nullptr; + } /* Return the list of all the solibs in this program space. */ owning_intrusive_list &solibs () @@ -401,8 +426,8 @@ private: /* All known objfiles are kept in a linked list. */ owning_intrusive_list m_objfiles_list; - /* solib_ops implementation used to provide solibs in this program space. */ - solib_ops_up m_solib_ops; + /* solib_ops implementations used to provide solibs in this program space. */ + std::vector m_solib_ops; /* List of shared objects mapped into this space. Managed by solib.c. */ diff --git a/gdb/solib-aix.c b/gdb/solib-aix.c index 28f69ed9cbb..28bae833efb 100644 --- a/gdb/solib-aix.c +++ b/gdb/solib-aix.c @@ -42,7 +42,7 @@ struct aix_solib_ops : public solib_ops solib_ops_up make_aix_solib_ops (program_space *pspace) { - return std::make_unique (pspace); + return std::make_unique (pspace, true); } /* Our private data in struct solib. */ diff --git a/gdb/solib-darwin.c b/gdb/solib-darwin.c index 07cd88d0e0c..11ed0bb154e 100644 --- a/gdb/solib-darwin.c +++ b/gdb/solib-darwin.c @@ -52,7 +52,7 @@ struct darwin_solib_ops : public solib_ops solib_ops_up make_darwin_solib_ops (program_space *pspace) { - return std::make_unique (pspace); + return std::make_unique (pspace, true); } struct gdb_dyld_image_info diff --git a/gdb/solib-dsbt.c b/gdb/solib-dsbt.c index 22b9a581546..54cd4257d55 100644 --- a/gdb/solib-dsbt.c +++ b/gdb/solib-dsbt.c @@ -138,7 +138,7 @@ struct dsbt_solib_ops : public solib_ops solib_ops_up make_dsbt_solib_ops (program_space *pspace) { - return std::make_unique (pspace); + return std::make_unique (pspace, true); } /* Link map info to include in an allocated solib entry */ diff --git a/gdb/solib-frv.c b/gdb/solib-frv.c index cff3c3ca019..7b444ecb3ea 100644 --- a/gdb/solib-frv.c +++ b/gdb/solib-frv.c @@ -46,7 +46,7 @@ struct frv_solib_ops : public solib_ops solib_ops_up make_frv_solib_ops (program_space *pspace) { - return std::make_unique (pspace); + return std::make_unique (pspace, true); } /* FR-V pointers are four bytes wide. */ diff --git a/gdb/solib-rocm.c b/gdb/solib-rocm.c index 6f8ba8c00ac..61b3dcaf716 100644 --- a/gdb/solib-rocm.c +++ b/gdb/solib-rocm.c @@ -28,7 +28,6 @@ #include "linux-tdep.h" #include "observable.h" #include "solib.h" -#include "solib-svr4.h" #include "symfile.h" #include "filesystem.h" @@ -171,33 +170,34 @@ rocm_solib_fd_cache::close (target_fd fd, fileio_error *target_errno) struct rocm_so { - rocm_so (const char *name, std::string unique_name, lm_info_svr4_up lm_info) - : name (name), + rocm_so (std::string name, std::string unique_name, CORE_ADDR load_addr) + : name (std::move (name)), unique_name (std::move (unique_name)), - lm_info (std::move (lm_info)) + load_addr (load_addr) {} std::string name, unique_name; - lm_info_svr4_up lm_info; + CORE_ADDR load_addr; +}; + +/* Private data for ROCm solibs. */ + +struct lm_info_rocm : public lm_info +{ + lm_info_rocm (CORE_ADDR load_addr) + : load_addr (load_addr) + {} + + CORE_ADDR load_addr; }; /* solib_ops for ROCm systems. */ struct rocm_solib_ops : public solib_ops { - /* HOST_OPS is the host solib_ops that rocm_solib_ops hijacks / wraps, - in order to provide support for ROCm code objects. */ - explicit rocm_solib_ops (inferior *inf, solib_ops_up host_ops) - : solib_ops (inf->pspace), m_host_ops (std::move (host_ops)), - m_inf (inf), m_fd_cache (inf) - { - gdb_assert (m_host_ops != nullptr); - gdb_assert (dynamic_cast (m_host_ops.get ()) == nullptr); - } - - /* Release the host solib_ops. */ - solib_ops_up release_host_ops () - { return std::move (m_host_ops); } + explicit rocm_solib_ops (inferior *inf) + : solib_ops (inf->pspace, false), m_inf (inf), m_fd_cache (inf) + { } /* The methods implemented by rocm_solib_ops. */ owning_intrusive_list current_sos () override; @@ -210,60 +210,11 @@ struct rocm_solib_ops : public solib_ops rocm_solib_target_inferior_created. */ void update_solib_list (); - /* Implement the following methods just to forward the calls to the host - solib_ops. We currently need to implement all the methods that - svr4_solib_ops implements. */ - void clear_so (const solib &so) const override - { return m_host_ops->clear_so (so); } - - void clear_solib (program_space *pspace) const override - { return m_host_ops->clear_solib (pspace); } - - bool open_symbol_file_object (int from_tty) const override - { return m_host_ops->open_symbol_file_object (from_tty); } - - bool in_dynsym_resolve_code (CORE_ADDR pc) const override - { return m_host_ops->in_dynsym_resolve_code (pc); } - - bool same (const solib &gdb, const solib &inferior) const override - { return m_host_ops->same (gdb, inferior); } - - bool keep_data_in_core (CORE_ADDR vaddr, unsigned long size) const override - { return m_host_ops->keep_data_in_core (vaddr, size); } - - void update_breakpoints () const override - { return m_host_ops->update_breakpoints (); } - - std::optional find_solib_addr (solib &so) const override - { return m_host_ops->find_solib_addr (so); } - - bool supports_namespaces () const override - { return m_host_ops->supports_namespaces (); } - - int find_solib_ns (const solib &so) const override - { return m_host_ops->find_solib_ns (so); } - - int num_active_namespaces () const override - { return m_host_ops->num_active_namespaces (); } - - std::vector get_solibs_in_ns (int nsid) const override - { return m_host_ops->get_solibs_in_ns (nsid); } - - void iterate_over_objfiles_in_search_order - (iterate_over_objfiles_in_search_order_cb_ftype cb, - objfile *current_objfile) const override - { - return m_host_ops->iterate_over_objfiles_in_search_order - (cb, current_objfile); - } - private: owning_intrusive_list solibs_from_rocm_sos (const std::vector &sos); gdb_bfd_iovec_base *bfd_iovec_open (bfd *abfd); - solib_ops_up m_host_ops; - /* Inferior this rocm_solib_ops is for. */ inferior *m_inf; @@ -280,28 +231,16 @@ void rocm_solib_ops::relocate_section_addresses (solib &so, struct target_section *sec) const { - if (!is_amdgpu_arch (so.abfd.get ())) - { - m_host_ops->relocate_section_addresses (so, sec); - return; - } + gdb_assert (is_amdgpu_arch (so.abfd.get ())); - auto *li = gdb::checked_static_cast (so.lm_info.get ()); - sec->addr = sec->addr + li->l_addr; - sec->endaddr = sec->endaddr + li->l_addr; + auto &li = gdb::checked_static_cast (*so.lm_info); + sec->addr = sec->addr + li.load_addr; + sec->endaddr = sec->endaddr + li.load_addr; } void rocm_solib_ops::handle_event () { - /* Since we sit on top of a host solib_ops, we might get called following an - event concerning host libraries. We must therefore forward the call. If - the event was for a ROCm code object, it will be a no-op. On the other hand - if the event was for host libraries, rocm_update_solib_list will be - essentially be a no-op (it will reload the same code object list as was - previously loaded). */ - m_host_ops->handle_event (); - this->update_solib_list (); } @@ -313,7 +252,7 @@ rocm_solib_ops::solibs_from_rocm_sos (const std::vector &sos) owning_intrusive_list dst; for (const rocm_so &so : sos) - dst.emplace_back (std::make_unique (*so.lm_info), + dst.emplace_back (std::make_unique (so.load_addr), so.unique_name, so.name, *this); return dst; @@ -325,22 +264,7 @@ rocm_solib_ops::solibs_from_rocm_sos (const std::vector &sos) owning_intrusive_list rocm_solib_ops::current_sos () { - /* First, retrieve the host-side shared library list. */ - owning_intrusive_list sos = m_host_ops->current_sos (); - - /* Then, the device-side shared library list. */ - if (m_solib_list.empty ()) - return sos; - - owning_intrusive_list dev_solibs = solibs_from_rocm_sos (m_solib_list); - - if (sos.empty ()) - return dev_solibs; - - /* Append our libraries to the end of the list. */ - sos.splice (std::move (dev_solibs)); - - return sos; + return solibs_from_rocm_sos (m_solib_list); } namespace { @@ -680,9 +604,7 @@ rocm_solib_ops::bfd_iovec_open (bfd *abfd) gdb_bfd_ref_ptr rocm_solib_ops::bfd_open (const char *pathname) { - /* Handle regular files with SVR4 open. */ - if (strstr (pathname, "://") == nullptr) - return m_host_ops->bfd_open (pathname); + gdb_assert (strstr (pathname, "://") != nullptr); auto open = [this] (bfd *nbfd) { @@ -769,7 +691,6 @@ void rocm_solib_ops::create_inferior_hook (int from_tty) { m_solib_list.clear (); - m_host_ops->create_inferior_hook (from_tty); } void @@ -816,10 +737,6 @@ rocm_solib_ops::update_solib_list () gdb::unique_xmalloc_ptr uri_bytes_holder (uri_bytes); - /* Pass a dummy debug base. */ - lm_info_svr4_up li = std::make_unique (-1); - li->l_addr = l_addr; - /* Generate a unique name so that code objects with the same URI but different load addresses are seen by gdb core as different shared objects. */ @@ -827,7 +744,7 @@ rocm_solib_ops::update_solib_list () = string_printf ("code_object_%ld", code_object_list[i].handle); m_solib_list.emplace_back (uri_bytes, std::move (unique_name), - std::move (li)); + l_addr); } } @@ -838,12 +755,10 @@ rocm_solib_target_inferior_created (inferior *inf) if (inf->vfork_parent != nullptr) return; - auto prev_ops = inf->pspace->release_solib_ops (); - auto rocm_ops = std::make_unique (inf, std::move (prev_ops)); - inf->pspace->set_solib_ops (std::move (rocm_ops)); + auto &rocm_ops + = inf->pspace->add_solib_ops (std::make_unique (inf)); - gdb::checked_static_cast - (inf->pspace->solib_ops ())->update_solib_list (); + rocm_ops.update_solib_list (); /* Force GDB to reload the solibs. */ inf->pspace->clear_solib_cache (); @@ -858,11 +773,8 @@ rocm_solib_target_inferior_execd (inferior *exec_inf, inferior *follow_inf) if (get_amd_dbgapi_process_id (follow_inf) == AMD_DBGAPI_PROCESS_NONE) return; - auto pspace = follow_inf->pspace; - auto prev_ops = pspace->release_solib_ops (); - auto rocm_ops - = std::make_unique (follow_inf, std::move (prev_ops)); - pspace->set_solib_ops (std::move (rocm_ops)); + follow_inf->pspace->add_solib_ops + (std::make_unique (follow_inf)); } static void @@ -872,31 +784,13 @@ rocm_solib_target_inferior_forked (inferior *parent_inf, inferior *child_inf, { if (detach_on_fork && follow_child && fork_kind == TARGET_WAITKIND_FORKED) { - /* In this particular configuration, infrun's follow_fork_inferior - function moves the parent pspace to the child directly. Remove the - existing rocm_solib_ops from the child and restore the host solib_ops, - to make it look like a brand new pspace. - - Remove solibs created by the rocm_solib_ops, since they contain back - references to the rocm_solib_ops (namely, to the fd cache). */ - auto &solibs = child_inf->pspace->solibs (); - auto rocm_ops - = gdb::checked_static_cast - (child_inf->pspace->solib_ops ()); - - for (auto solibs_it = solibs.begin (); solibs_it != solibs.end ();) - { - if (&solibs_it->ops () != rocm_ops) - { - ++solibs_it; - continue; - } - - solibs_it = remove_solib (child_inf->pspace, solibs_it); - } - - auto rocm_ops_holder = child_inf->pspace->release_solib_ops (); - child_inf->pspace->set_solib_ops (rocm_ops->release_host_ops ()); + /* In this particular configuration, infrun's follow_fork_inferior moves + the parent pspace to the child directly. Remove the existing rocm_solib_ops + from the child and restore the host solib_ops, to make it look like a + brand new pspace. */ + auto rocm_ops = child_inf->pspace->find_solib_ops (); + gdb_assert (rocm_ops != nullptr); + child_inf->pspace->remove_solib_ops (*rocm_ops); } } diff --git a/gdb/solib-svr4.c b/gdb/solib-svr4.c index 33fb6e3cd97..04000f6797e 100644 --- a/gdb/solib-svr4.c +++ b/gdb/solib-svr4.c @@ -3639,7 +3639,7 @@ find_debug_base_for_solib (const solib *solib) stay in the same namespace as that file. Otherwise, we only consider the initial namespace. */ -void +bool svr4_solib_ops::iterate_over_objfiles_in_search_order (iterate_over_objfiles_in_search_order_cb_ftype cb, objfile *current_objfile) const @@ -3665,7 +3665,7 @@ svr4_solib_ops::iterate_over_objfiles_in_search_order { checked_current_objfile = true; if (cb (current_objfile)) - return; + return true; } } @@ -3686,13 +3686,25 @@ svr4_solib_ops::iterate_over_objfiles_in_search_order if (checked_current_objfile && &objfile == current_objfile) continue; - /* Try to determine the namespace into which objfile was loaded. - - If we fail, e.g. for manually added symbol files or for the main - executable, we assume that they were added to the initial - namespace. */ const solib *solib = find_one_solib_for_objfile (&objfile); - CORE_ADDR solib_base = find_debug_base_for_solib (solib); + CORE_ADDR solib_base = 0; + + if (solib != nullptr) + { + /* Skip objfiles provided by other solib_ops. */ + if (&solib->ops () != this) + continue; + + solib_base = find_debug_base_for_solib (solib); + } + else if (&objfile != m_pspace->symfile_object_file) + { + /* Objfiles not associated to an solib_ops are handled in the + program_space method. The main objfile is an exception to this, + because it is part of the SVR4 domain. */ + continue; + } + if (solib_base == 0) solib_base = default_debug_base; @@ -3701,8 +3713,10 @@ svr4_solib_ops::iterate_over_objfiles_in_search_order continue; if (cb (&objfile)) - return; + return true; } + + return false; } std::optional diff --git a/gdb/solib-svr4.h b/gdb/solib-svr4.h index d7f58a76224..69b79d051d3 100644 --- a/gdb/solib-svr4.h +++ b/gdb/solib-svr4.h @@ -94,7 +94,9 @@ enum probe_action struct svr4_solib_ops : public solib_ops { - using solib_ops::solib_ops; + explicit svr4_solib_ops (program_space *pspace) + : solib_ops (pspace, true) + {} void relocate_section_addresses (solib &so, target_section *) const override; void clear_so (const solib &so) const override; @@ -112,7 +114,7 @@ struct svr4_solib_ops : public solib_ops int find_solib_ns (const solib &so) const override; int num_active_namespaces () const override; std::vector get_solibs_in_ns (int nsid) const override; - void iterate_over_objfiles_in_search_order + bool iterate_over_objfiles_in_search_order (iterate_over_objfiles_in_search_order_cb_ftype cb, objfile *current_objfile) const override; diff --git a/gdb/solib-target.c b/gdb/solib-target.c index 0df8c6048ae..28558a03f5b 100644 --- a/gdb/solib-target.c +++ b/gdb/solib-target.c @@ -390,5 +390,5 @@ target_solib_ops::in_dynsym_resolve_code (CORE_ADDR pc) const solib_ops_up make_target_solib_ops (program_space *pspace) { - return std::make_unique (pspace); + return std::make_unique (pspace, true); } diff --git a/gdb/solib.c b/gdb/solib.c index 6ed56aaf515..ef5d2024751 100644 --- a/gdb/solib.c +++ b/gdb/solib.c @@ -21,6 +21,7 @@ #include #include "exceptions.h" #include "extract-store-integer.h" +#include "progspace.h" #include "symtab.h" #include "bfd.h" #include "build-id.h" @@ -446,17 +447,38 @@ solib_ops::bfd_open (const char *pathname) /* See solib.h. */ -void +bool solib_ops::iterate_over_objfiles_in_search_order (iterate_over_objfiles_in_search_order_cb_ftype cb, objfile *current_objfile) const { if (current_objfile != nullptr && cb (current_objfile)) - return; + return true; for (objfile &objfile : m_pspace->objfiles ()) - if (&objfile != current_objfile && cb (&objfile)) - return; + { + /* The current objfile, if any, was handled above. */ + if (current_objfile == &objfile) + continue; + + /* Call CB on OBJFILE if either: + + - OBJFILE was provided by this solib_ops, or + - this is the main objfile and M_HANDLE_MAIN_OBJFILE is true + */ + bool is_from_this = (!objfile.solibs ().empty () + && &objfile.solibs ().front ()->ops () == this); + bool is_main_handled_by_this = (&objfile == m_pspace->symfile_object_file + && m_handle_main_objfile); + + if (!is_from_this && !is_main_handled_by_this) + continue; + + if (cb (&objfile)) + return true; + } + + return false; } /* Given a pointer to one of the shared objects in our list of mapped @@ -742,11 +764,6 @@ remove_solib (program_space *pspace, void update_solib_list (int from_tty) { - solib_ops *ops = current_program_space->solib_ops (); - - if (ops == nullptr) - return; - /* We can reach here due to changing solib-search-path or the sysroot, before having any inferior. */ if (target_has_execution () && inferior_ptid != null_ptid) @@ -761,7 +778,9 @@ update_solib_list (int from_tty) { try { - ops->open_symbol_file_object (from_tty); + for (const auto &ops : current_program_space->solib_ops ()) + if (ops->open_symbol_file_object (from_tty)) + break; } catch (const gdb_exception_error &ex) { @@ -796,7 +815,10 @@ update_solib_list (int from_tty) the time we're done walking GDB's list, the inferior's list contains only the new shared objects, which we then add. */ - owning_intrusive_list inferior = ops->current_sos (); + owning_intrusive_list inferior; + for (auto &ops : current_program_space->solib_ops ()) + inferior.splice (ops->current_sos ()); + owning_intrusive_list::iterator gdb_iter = current_program_space->solibs ().begin (); while (gdb_iter != current_program_space->solibs ().end ()) @@ -806,8 +828,13 @@ update_solib_list (int from_tty) /* Check to see whether the shared object *gdb also appears in the inferior's current list. */ for (; inferior_iter != inferior.end (); ++inferior_iter) - if (ops->same (*gdb_iter, *inferior_iter)) - break; + { + if (&gdb_iter->ops () != &inferior_iter->ops ()) + continue; + + if (gdb_iter->ops ().same (*gdb_iter, *inferior_iter)) + break; + } /* If the shared object appears on the inferior's list too, then it's still loaded, so we don't need to do anything. Delete @@ -1024,25 +1051,28 @@ print_solib_list_table (std::vector solib_list, gdbarch *gdbarch = current_inferior ()->arch (); /* "0x", a little whitespace, and two hex digits per byte of pointers. */ int addr_width = 4 + (gdbarch_ptr_bit (gdbarch) / 4); - const solib_ops *ops = current_program_space->solib_ops (); struct ui_out *uiout = current_uiout; bool so_missing_debug_info = false; - if (ops == nullptr) - return; + /* The conditions for this command to print solib namespaces: - /* There are 3 conditions for this command to print solib namespaces, - first PRINT_NAMESPACE has to be true, second the solib_ops has to - support multiple namespaces, and third there must be more than one - active namespace. Fold all these into the PRINT_NAMESPACE condition. */ - print_namespace = (print_namespace - && ops != nullptr - && ops->supports_namespaces () - && ops->num_active_namespaces () > 1); + - PRINT_NAMESPACE has to be true + - at least one solib_ops has to have more than one active namespace - int num_cols = 4; + Fold these into the PRINT_NAMESPACE condition. */ if (print_namespace) - num_cols++; + { + print_namespace = false; + + for (auto &ops : current_program_space->solib_ops ()) + if (ops->supports_namespaces () && ops->num_active_namespaces () > 1) + { + print_namespace = true; + break; + } + } + + int num_cols = print_namespace ? 5 : 4; { ui_out_emit_table table_emitter (uiout, num_cols, solib_list.size (), @@ -1080,7 +1110,11 @@ print_solib_list_table (std::vector solib_list, { try { - uiout->field_fmt ("namespace", "%d", ops->find_solib_ns (*so)); + if (so->ops ().supports_namespaces ()) + uiout->field_fmt ("namespace", "%d", + so->ops ().find_solib_ns (*so)); + else + uiout->field_skip ("namespace"); } catch (const gdb_exception_error &er) { @@ -1163,81 +1197,92 @@ info_sharedlibrary_command (const char *pattern, int from_tty) static void info_linker_namespace_command (const char *pattern, int from_tty) { - const solib_ops *ops = current_program_space->solib_ops (); - - /* This command only really makes sense for inferiors that support - linker namespaces, so we can leave early. */ - if (ops == nullptr || !ops->supports_namespaces ()) - error (_("Current inferior does not support linker namespaces. " - "Use \"info sharedlibrary\" instead.")); - - struct ui_out *uiout = current_uiout; - std::vector>> all_solibs_to_print; - pattern = skip_spaces (pattern); - if (pattern == nullptr || pattern[0] == '\0') - { - uiout->message (_("There are %d linker namespaces loaded.\n"), - ops->num_active_namespaces ()); + /* Will be set to true if at least one solib_ops in the program space + supports namespaces. */ + bool one_solib_ops_supports_namespaces = false; - int printed = 0; - for (int i = 0; printed < ops->num_active_namespaces (); i++) + for (auto &ops : current_program_space->solib_ops ()) + { + if (!ops->supports_namespaces ()) + continue; + + one_solib_ops_supports_namespaces = true; + + struct ui_out *uiout = current_uiout; + std::vector>> + all_solibs_to_print; + + if (pattern == nullptr || pattern[0] == '\0') { - std::vector solibs_to_print - = ops->get_solibs_in_ns (i); - if (solibs_to_print.size () > 0) + /* The output here will be awkward if multiple solib_ops support + namespaces, but it's just theoretical for now, so don't bother + trying to do anything fancier. */ + uiout->message (_("There are %d linker namespaces loaded.\n"), + ops->num_active_namespaces ()); + + int printed = 0; + for (int i = 0; printed < ops->num_active_namespaces (); i++) { - all_solibs_to_print.push_back (std::make_pair - (i, solibs_to_print)); - printed++; + std::vector solibs_to_print + = ops->get_solibs_in_ns (i); + if (solibs_to_print.size () > 0) + { + all_solibs_to_print.push_back (std::make_pair + (i, solibs_to_print)); + printed++; + } } } - } - else - { - int ns; - /* Check if the pattern includes the optional [[ and ]] decorators. - To match multiple occurrences, '+' needs to be escaped, and every - escape sequence must be doubled to survive the compiler pass. */ - re_comp ("^\\[\\[[0-9]\\+\\]\\]$"); - if (re_exec (pattern)) - ns = strtol (pattern + 2, nullptr, 10); else { - char *end = nullptr; - ns = strtol (pattern, &end, 10); - if (end[0] != '\0') - error (_("Invalid linker namespace identifier: %s"), pattern); + int ns; + /* Check if the pattern includes the optional [[ and ]] decorators. + To match multiple occurrences, '+' needs to be escaped, and every + escape sequence must be doubled to survive the compiler pass. */ + re_comp ("^\\[\\[[0-9]\\+\\]\\]$"); + if (re_exec (pattern)) + ns = strtol (pattern + 2, nullptr, 10); + else + { + char *end = nullptr; + ns = strtol (pattern, &end, 10); + if (end[0] != '\0') + error (_("Invalid linker namespace identifier: %s"), pattern); + } + + all_solibs_to_print.push_back + (std::make_pair (ns, ops->get_solibs_in_ns (ns))); } - all_solibs_to_print.push_back - (std::make_pair (ns, ops->get_solibs_in_ns (ns))); - } - - for (const auto &[ns, solibs_to_print] : all_solibs_to_print) - { - uiout->message ("\n"); - - if (solibs_to_print.size () == 0) + for (const auto &[ns, solibs_to_print] : all_solibs_to_print) { - uiout->message (_("Linker namespace %d is not active.\n"), ns); - /* If we got here, a specific namespace was requested, so there - will only be one vector. We can leave early. */ - break; + uiout->message ("\n"); + + if (solibs_to_print.size () == 0) + { + uiout->message (_("Linker namespace %d is not active.\n"), ns); + /* If we got here, a specific namespace was requested, so there + will only be one vector. We can leave early. */ + break; + } + + if (solibs_to_print.size () == 1) + uiout->message + (_("1 library loaded in linker namespace %d:\n"), ns); + else + uiout->message + (_("%zu libraries loaded in linker namespace %d:\n"), + solibs_to_print.size (), ns); + + print_solib_list_table (solibs_to_print, false); } - - if (solibs_to_print.size () == 1) - uiout->message - (_("1 library loaded in linker namespace %d:\n"), ns); - else - uiout->message - (_("%zu libraries loaded in linker namespace %d:\n"), - solibs_to_print.size (), ns); - - - print_solib_list_table (solibs_to_print, false); } + + if (!one_solib_ops_supports_namespaces) + error (_("Current inferior does not support linker namespaces. " + "Use \"info sharedlibrary\" instead.")); } /* See solib.h. */ @@ -1285,9 +1330,11 @@ solib_ops::same (const solib &a, const solib &b) const bool solib_keep_data_in_core (CORE_ADDR vaddr, unsigned long size) { - const solib_ops *ops = current_program_space->solib_ops (); + for (const auto &ops : current_program_space->solib_ops ()) + if (ops->keep_data_in_core (vaddr, size)) + return true; - return ops != nullptr && ops->keep_data_in_core (vaddr, size); + return false; } /* See solib.h. */ @@ -1306,8 +1353,7 @@ clear_solib (program_space *pspace) pspace->solibs ().clear (); - if (const solib_ops *ops = pspace->solib_ops (); - ops != nullptr) + for (const auto &ops : pspace->solib_ops ()) ops->clear_solib (pspace); } @@ -1319,8 +1365,7 @@ clear_solib (program_space *pspace) void solib_create_inferior_hook (int from_tty) { - if (solib_ops *ops = current_program_space->solib_ops (); - ops != nullptr) + for (const auto &ops : current_program_space->solib_ops ()) ops->create_inferior_hook (from_tty); } @@ -1329,9 +1374,11 @@ solib_create_inferior_hook (int from_tty) bool in_solib_dynsym_resolve_code (CORE_ADDR pc) { - const solib_ops *ops = current_program_space->solib_ops (); + for (const auto &ops : current_program_space->solib_ops ()) + if (ops->in_dynsym_resolve_code (pc)) + return true; - return ops != nullptr && ops->in_dynsym_resolve_code (pc); + return false; } /* Implements the "sharedlibrary" command. */ @@ -1373,9 +1420,7 @@ no_shared_libraries_command (const char *ignored, int from_tty) void update_solib_breakpoints (void) { - const solib_ops *ops = current_program_space->solib_ops (); - - if (ops != nullptr) + for (const auto &ops : current_program_space->solib_ops ()) ops->update_breakpoints (); } @@ -1384,8 +1429,7 @@ update_solib_breakpoints (void) void handle_solib_event (void) { - if (solib_ops *ops = current_program_space->solib_ops (); - ops != nullptr) + for (const auto &ops : current_program_space->solib_ops ()) ops->handle_event (); current_inferior ()->pspace->clear_solib_cache (); @@ -1483,8 +1527,7 @@ reload_shared_libraries (const char *ignored, int from_tty, { /* Reset or free private data structures not associated with solib entries. */ - if (const solib_ops *ops = current_program_space->solib_ops (); - ops != nullptr) + for (const auto &ops : current_program_space->solib_ops ()) ops->clear_solib (current_program_space); /* Remove any previous solib event breakpoint. This is usually @@ -1816,11 +1859,13 @@ remove_user_added_objfile (struct objfile *objfile) int solib_linker_namespace_count (program_space *pspace) { - if (const auto ops = pspace->solib_ops (); ops != nullptr - && ops->supports_namespaces ()) - return ops->num_active_namespaces (); + int num_active_namespaces = 0; - return 0; + for (const auto &ops : pspace->solib_ops ()) + if (ops->supports_namespaces ()) + num_active_namespaces += ops->num_active_namespaces (); + + return num_active_namespaces; } /* Implementation of the linker_namespace convenience variable. diff --git a/gdb/solib.h b/gdb/solib.h index 903b9d7b2a8..4ca3c205ef2 100644 --- a/gdb/solib.h +++ b/gdb/solib.h @@ -140,8 +140,8 @@ using iterate_over_objfiles_in_search_order_cb_ftype struct solib_ops { - explicit solib_ops (program_space *pspace) - : m_pspace (pspace) + solib_ops (program_space *pspace, bool handle_main_objfile) + : m_pspace (pspace), m_handle_main_objfile (handle_main_objfile) {} virtual ~solib_ops () = default; @@ -271,21 +271,29 @@ struct solib_ops virtual std::vector get_solibs_in_ns (int ns) const { gdb_assert_not_reached ("namespaces not supported"); } - /* Iterate over all objfiles of the program space in the order that makes the - most sense for the architecture to make global symbol searches. + /* Iterate over all objfiles associated to this solib_ops in the order that + makes the most sense for the architecture to make global symbol searches. + + If M_HANDLE_MAIN_OBJFILE is set, also iterate over the "main" objfile of + the program space (program_space::symfile_object_file). CB is a callback function passed an objfile to be searched. The iteration stops if this function returns true. If not nullptr, CURRENT_OBJFILE corresponds to the objfile being inspected - when the symbol search was requested. */ - virtual void iterate_over_objfiles_in_search_order + when the symbol search was requested. If not nullptr, it is guaranteed + that CURRENT_OBJFILE is associated to this solib_ops. */ + virtual bool iterate_over_objfiles_in_search_order (iterate_over_objfiles_in_search_order_cb_ftype cb, objfile *current_objfile) const; protected: /* The program space for which this solib_ops was created. */ program_space *m_pspace; + + /* Whether this solib_ops should handle the main objfile + (pspace->symfile_object_file) in iterate_over_objfiles_in_search_order. */ + bool m_handle_main_objfile; }; /* A unique pointer to an solib_ops. */ diff --git a/gdb/target.c b/gdb/target.c index 5d937f3ae85..e680943d5b2 100644 --- a/gdb/target.c +++ b/gdb/target.c @@ -2482,7 +2482,7 @@ target_pre_inferior () if (!gdbarch_has_global_solist (current_inferior ()->arch ())) { no_shared_libraries (current_program_space); - current_program_space->unset_solib_ops (); + current_program_space->clear_solib_ops (); invalidate_target_mem_regions (); diff --git a/gdb/testsuite/gdb.rocm/symbol-lookup.cpp b/gdb/testsuite/gdb.rocm/symbol-lookup.cpp new file mode 100644 index 00000000000..7de2f6a3499 --- /dev/null +++ b/gdb/testsuite/gdb.rocm/symbol-lookup.cpp @@ -0,0 +1,320 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2022-2025 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 . */ + +#if defined(SHARED_LIB_1) + +extern "C" +{ + + using shared_lib_1_t = int; + + void func_host_shared_lib_1 (shared_lib_1_t) + { + } + + void func_host_shared_lib (shared_lib_1_t) + { + } + + void func_1 (shared_lib_1_t) + { + } + + void func_main_shared_lib_1 (shared_lib_1_t) + { + } + +} /* extern "C" */ + +#elif defined(SHARED_LIB_2) + +extern "C" +{ + + using shared_lib_2_t = int; + + void func_host_shared_lib_2 (shared_lib_2_t) + { + } + + void func_host_shared_lib (shared_lib_2_t) + { + } + + void func_2 (shared_lib_2_t) + { + } + + void func_main_shared_lib_2 (shared_lib_2_t) + { + } + +} /* extern "C" */ + +#elif defined(CODE_OBJECT_1) + +extern "C" +{ + + using code_object_1_t = int; + + __global__ void func_device_code_object_1 (code_object_1_t) + { + } + + __global__ void func_device_code_object (code_object_1_t) + { + } + + __global__ void func_1 (code_object_1_t) + { + } + + __global__ void func_main_code_object_1 (code_object_1_t) + { + } + +} /* extern "C" */ + +#elif defined(CODE_OBJECT_2) + +extern "C" +{ + + using code_object_2_t = int; + + __global__ void func_device_code_object_2 (code_object_2_t) + { + } + + __global__ void func_device_code_object (code_object_2_t) + { + } + + __global__ void func_2 (code_object_2_t) + { + } + + __global__ void func_main_code_object_2 (code_object_2_t) + { + } + +} /* extern "C" */ + +#else + +#include +#include +#include +#include +#include "hip/hip_runtime.h" + +/* This `extern "C"` is necessary to make the test work, due to an oddity in how + GDB computes the demangled names. Without it, the compiler includes a + DW_AT_linkage_name in the DW_TAG_subprogram DIE, causing GDB to use that to + compute the symbol's demangled name. The symbols would then appear as + `func_main(int)` rather than `func_main(main_program_t)`, making it + impossible to differentiate them. With `extern "C"`, GDB has to construct + the demangled name from the DIE structure, resulting in the expected + `func_main(main_program_t)`. */ + +extern "C" +{ + + using main_program_t = int; + + void func_main (main_program_t) + { + } + + void func_main_shared_lib_1 (main_program_t) + { + } + + void func_main_shared_lib_2 (main_program_t) + { + } + + void func_main_code_object_1 (main_program_t) + { + } + + void func_main_code_object_2 (main_program_t) + { + } + +} /* extern "C" */ + +namespace +{ + +void +throw_from_hip_error (const std::string &prefix, hipError_t error) +{ + throw std::runtime_error (prefix + ": " + hipGetErrorString (error)); +} + +void +warn_from_hip_error (const std::string &prefix, hipError_t error) +{ + std::cerr << prefix + ": " + hipGetErrorString (error) << std::endl; +} + +struct hip_module_unloader +{ + void operator() (hipModule_t module) const + { + hipError_t error = hipModuleUnload (module); + + if (error != HIP_SUCCESS) + warn_from_hip_error ("Failed to unload HIP module", error); + } +}; + +using hip_module_up + = std::unique_ptr, hip_module_unloader>; + +hip_module_up +load_hip_module (const char *module_path) +{ + hipModule_t module; + hipError_t error = hipModuleLoad (&module, module_path); + + if (error != HIP_SUCCESS) + throw_from_hip_error ((std::string ("Failed to load HIP module ") + + module_path), + error); + + return hip_module_up (module); +} + +void +throw_from_dlerror (const std::string &prefix) +{ + throw std::runtime_error (prefix + ": " + dlerror ()); +} + +void +warn_from_dlerror (const std::string &prefix) +{ + std::cerr << prefix + ": " + dlerror () << std::endl; +} + +struct dlcloser +{ + void operator() (void *lib) + { + int ret = dlclose (lib); + + if (ret != 0) + warn_from_dlerror ("Failed to dlclose"); + } +}; + +using dl_up = std::unique_ptr; + +dl_up +load_shared_lib (const char *lib_path) +{ + void *lib = dlopen (lib_path, RTLD_NOW); + + if (lib == nullptr) + throw_from_dlerror (std::string ("Failed to dlopen ") + lib_path); + + return dl_up (lib); +} + +using host_function_t = void (*) (int); + +host_function_t +lookup_symbol (dl_up &dl, const char *sym_name) +{ + void *sym = dlsym (dl.get (), sym_name); + + if (sym == nullptr) + throw_from_dlerror (std::string ("Failed to dlsym ") + sym_name); + + return reinterpret_cast (sym); +} + +hipFunction_t +lookup_symbol (hip_module_up &mod, const char *sym_name) +{ + hipFunction_t func; + hipError_t error = hipModuleGetFunction (&func, mod.get (), sym_name); + + if (error != HIP_SUCCESS) + throw_from_hip_error (std::string ("Failed to look up kernel ") + sym_name, + error); + + return func; +} + +void +launch_kernel (hipFunction_t func) +{ + int arg = 2; + void *args[1] = { &arg }; + + hipError_t error = hipModuleLaunchKernel (func, 1, 1, 1, 1, 1, 1, 0, nullptr, + args, nullptr); + + if (error != HIP_SUCCESS) + throw_from_hip_error ("Failed to launch kernel", error); + + error = hipDeviceSynchronize (); + + if (error != HIP_SUCCESS) + throw_from_hip_error ("Failed to sync", error); +} + +} /* namespace */ + +int +main (int argc, const char **argv) +{ + if (argc != 5) + { + fprintf (stderr, "Usage: %s \n", argv[0]); + return 1; + } + + dl_up shared_lib_1 = load_shared_lib (argv[1]); + dl_up shared_lib_2 = load_shared_lib (argv[2]); + hip_module_up hip_module_1 = load_hip_module (argv[3]); + hip_module_up hip_module_2 = load_hip_module (argv[4]); + + host_function_t shared_lib_1_sym + = lookup_symbol (shared_lib_1, "func_host_shared_lib_1"); + host_function_t shared_lib_2_sym + = lookup_symbol (shared_lib_2, "func_host_shared_lib_2"); + + hipFunction_t code_object_1_kernel + = lookup_symbol (hip_module_1, "func_device_code_object_1"); + hipFunction_t code_object_2_kernel + = lookup_symbol (hip_module_2, "func_device_code_object_2"); + + func_main (0); + shared_lib_1_sym (0); + shared_lib_2_sym (0); + launch_kernel (code_object_1_kernel); + launch_kernel (code_object_2_kernel); + + return 0; +} + +#endif diff --git a/gdb/testsuite/gdb.rocm/symbol-lookup.exp b/gdb/testsuite/gdb.rocm/symbol-lookup.exp new file mode 100644 index 00000000000..1eb658a3e4c --- /dev/null +++ b/gdb/testsuite/gdb.rocm/symbol-lookup.exp @@ -0,0 +1,243 @@ +# Copyright 2025 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 . + +# Test symbol lookup with multiple host shared libraries and ROCm code objects. +# +# This test verifies that GDB correctly resolves symbols based on where the +# program is stopped. The following objfiles are in play: +# +# - the main program +# - two host shared libraries +# - two ROCm code objects +# +# The main program is separated from host shared libraries for the purpose of +# this test because it is handled differently than shared libraries by the +# iterate_over_objfiles_in_search_order methods. +# +# Each objfile defines functions with various levels of uniqueness: +# +# - func_main: unique to the main program +# - func_host_shared_lib_N: unique to host shared library N +# - func_device_code_object_N: unique to ROCm code object N +# - func_host_shared_lib: defined in both host shared libraries +# - func_device_code_object: defined in both ROCm code objects +# - func_N: defined in host shared library N and ROCm code object N +# - func_main_shared_lib_N: defined in the main program and host shared library N +# - func_main_code_object_N: defined in the main program and ROCm code object N +# +# The functions have different signatures, to be able to tell them apart. +# +# The test stops at breakpoints in each objfile and verifies that symbol +# lookups return the expected function. GDB gives priority to the current +# objfile, and then objfiles from the current "solib provider", before +# considering other loaded objfiles. + +load_lib rocm.exp + +standard_testfile .cpp + +require allow_hipcc_tests + +# Build the main program. +if { [build_executable "failed to prepare" \ + $testfile $srcfile {debug hip}] == -1 } { + return +} + +# Return the path to shared library N. +proc shared_lib_path { n } { + return [standard_output_file ${::testfile}_${n}.so] +} + +# Return the path to code object N. +proc code_object_path { n } { + return [standard_output_file ${::testfile}_${n}.co] +} + +# Build the host shared libraries and ROCm code objects. +foreach n {1 2} { + set shared_lib [shared_lib_path $n] + set code_object [code_object_path $n] + + # Build the host shlib N + if { [gdb_compile_shlib $srcdir/$subdir/$srcfile $shared_lib \ + [list debug additional_flags=-DSHARED_LIB_$n]] != "" } { + return + } + + # Build the ROCm code object N + if { [gdb_compile $srcdir/$subdir/$srcfile $code_object object \ + [list debug hip additional_flags=--genco additional_flags=-DCODE_OBJECT_$n]] != "" } { + return + } +} + +# Verify symbol lookup results at the current stop location. +# +# Each parameter is a regex matching the expected parameter type in the +# function signature. This parameter type is what allows us to confirm +# that GDB found the expected version of the function. +proc check_funcs { func_host_shared_lib func_device_code_object + func_1 func_2 + func_main_shared_lib_1 func_main_shared_lib_2 + func_main_code_object_1 func_main_code_object_2 } { + # Unique functions: only one definition exists, so lookup is unambiguous. + gdb_test "print func_main" "" + gdb_test "print func_host_shared_lib_1" "" + gdb_test "print func_host_shared_lib_2" "" + gdb_test "print func_device_code_object_1" "" + gdb_test "print func_device_code_object_2" "" + + # Functions defined in either both host shlibs or both code objects. + gdb_test "print func_host_shared_lib" "" + gdb_test "print func_device_code_object" "" + + # Functions defined in one host shlib and one code object. + gdb_test "print func_1" "" + gdb_test "print func_2" "" + + # Functions defined in main program and one objfile. + gdb_test "print func_main_shared_lib_1" "" + gdb_test "print func_main_shared_lib_2" "" + gdb_test "print func_main_code_object_1" "" + gdb_test "print func_main_code_object_2" "" +} + +proc do_test {} { + clean_restart + gdb_load $::binfile + + set shared_lib_1 [shared_lib_path 1] + set shared_lib_2 [shared_lib_path 2] + set code_object_1 [code_object_path 1] + set code_object_2 [code_object_path 2] + + gdb_test_no_output "set args $shared_lib_1 $shared_lib_2 $code_object_1 $code_object_2" \ + "set args" + + with_rocm_gpu_lock { + if ![runto_main] { + return + } + + # Set a breakpoint in the main program after all libraries / code + # objects have been loaded, as well as one breakpoint in each objfile. + gdb_test "break func_main" \ + "Breakpoint $::decimal at $::hex.*" + gdb_test "with breakpoint pending on -- break func_host_shared_lib_1" \ + "Breakpoint $::decimal \\(func_host_shared_lib_1\\) pending." + gdb_test "with breakpoint pending on -- break func_host_shared_lib_2" \ + "Breakpoint $::decimal \\(func_host_shared_lib_2\\) pending." + gdb_test "with breakpoint pending on -- break func_device_code_object_1" \ + "Breakpoint $::decimal \\(func_device_code_object_1\\) pending." + gdb_test "with breakpoint pending on -- break func_device_code_object_2" \ + "Breakpoint $::decimal \\(func_device_code_object_2\\) pending." + + # Stop in main program. We expect: + # - func_host_shared_lib to resolve to either shared lib (no preference) + # - func_device_code_object to resolve to either code object (no preference) + # - func_1 to resolve to shared_lib_1 (current solib provider) + # - func_2 to resolve to shared_lib_2 (current solib provider) + # - func_main_* symbols to resolve to main program's version (current objfile) + with_test_prefix "main program" { + gdb_test "continue" "hit Breakpoint $::decimal, func_main .*" + check_funcs \ + "shared_lib_._t" \ + "code_object_._t" \ + "shared_lib_1_t" \ + "shared_lib_2_t" \ + "main_program_t" \ + "main_program_t" \ + "main_program_t" \ + "main_program_t" + } + + # Stop in host shared library 1. We expect: + # - func_host_shared_lib to resolve to shared_lib_1's version (current objfile) + # - func_device_code_object to resolve to either code object (no preference) + # - func_1 to resolve to shared_lib_1's version (current objfile) + # - func_2 to resolve to shared_lib_2's version (current solib provider) + # - func_main_shared_lib_1 to resolve to shared_lib_1's version (current objfile) + # - func_main_shared_lib_2 to resolve to either main or shared_lib_2 (no preference) + # - func_main_code_object_1 to resolve to either main or code_object_1 (no preference) + # - func_main_code_object_2 to resolve to either main or code_object_2 (no preference) + with_test_prefix "host shared lib 1" { + gdb_test "continue" "hit Breakpoint $::decimal, func_host_shared_lib_1 .*" + check_funcs \ + "shared_lib_1_t" \ + "code_object_._t" \ + "shared_lib_1_t" \ + "shared_lib_2_t" \ + "shared_lib_1_t" \ + "(main_program_t|shared_lib_2_t)" \ + "(main_program_t|code_object_1_t)" \ + "(main_program_t|code_object_2_t)" + } + + # Stop in host shared library 2. Similar logic but now shared_lib_2 + # is the current objfile. + with_test_prefix "host shared lib 2" { + gdb_test "continue" "hit Breakpoint $::decimal, func_host_shared_lib_2 .*" + check_funcs \ + "shared_lib_2_t" \ + "code_object_._t" \ + "shared_lib_1_t" \ + "shared_lib_2_t" \ + "(main_program_t|shared_lib_1_t)" \ + "shared_lib_2_t" \ + "(main_program_t|code_object_1_t)" \ + "(main_program_t|code_object_2_t)" + } + + # Stop in ROCm code object 1. We expect: + # - func_host_shared_lib to resolve to either shared lib (no preference) + # - func_device_code_object to resolve to code_object_1's version (current objfile) + # - func_1 to resolve to code_object_1's version (current objfile) + # - func_2 to resolve to code_object_2's version (current solib provider) + # - func_main_shared_lib_1 to resolve to either main or shared_lib_1 (no preference) + # - func_main_shared_lib_2 to resolve to either main or shared_lib_2 (no preference) + # - func_main_code_object_1 to resolve to code_object_1's version (current objfile) + # - func_main_code_object_2 to resolve to either main or code_object_2 (no preference) + with_test_prefix "device code object 1" { + gdb_test "continue" "hit Breakpoint $::decimal, func_device_code_object_1 .*" + check_funcs \ + "shared_lib_._t" \ + "code_object_1_t" \ + "code_object_1_t" \ + "code_object_2_t" \ + "(main_program_t|shared_lib_1_t)" \ + "(main_program_t|shared_lib_2_t)" \ + "code_object_1_t" \ + "(main_program_t|code_object_2_t)" + } + + # Stop in ROCm code object 2. Similar logic but now code_object_2 + # is the current objfile. + with_test_prefix "device code object 2" { + gdb_test "continue" "hit Breakpoint $::decimal, func_device_code_object_2 .*" + check_funcs \ + "shared_lib_._t" \ + "code_object_2_t" \ + "code_object_1_t" \ + "code_object_2_t" \ + "(main_program_t|shared_lib_1_t)" \ + "(main_program_t|shared_lib_2_t)" \ + "(main_program_t|code_object_1_t)" \ + "code_object_2_t" + } + } +} + +do_test diff --git a/gdb/windows-tdep.c b/gdb/windows-tdep.c index d65e6e76fae..2201c17818b 100644 --- a/gdb/windows-tdep.c +++ b/gdb/windows-tdep.c @@ -836,7 +836,7 @@ struct windows_solib_ops : target_solib_ops static solib_ops_up make_windows_solib_ops (program_space *pspace) { - return std::make_unique (pspace); + return std::make_unique (pspace, true); } /* Implement the "solib_create_inferior_hook" solib_ops method. */