Home | History | Annotate | Line # | Download | only in gdb
solib-rocm.c revision 1.1
      1 /* Handle ROCm Code Objects for GDB, the GNU Debugger.
      2 
      3    Copyright (C) 2019-2024 Free Software Foundation, Inc.
      4 
      5    This file is part of GDB.
      6 
      7    This program is free software; you can redistribute it and/or modify
      8    it under the terms of the GNU General Public License as published by
      9    the Free Software Foundation; either version 3 of the License, or
     10    (at your option) any later version.
     11 
     12    This program is distributed in the hope that it will be useful,
     13    but WITHOUT ANY WARRANTY; without even the implied warranty of
     14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15    GNU General Public License for more details.
     16 
     17    You should have received a copy of the GNU General Public License
     18    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
     19 
     20 
     21 #include "amd-dbgapi-target.h"
     22 #include "amdgpu-tdep.h"
     23 #include "arch-utils.h"
     24 #include "elf-bfd.h"
     25 #include "elf/amdgpu.h"
     26 #include "event-top.h"
     27 #include "gdbsupport/fileio.h"
     28 #include "inferior.h"
     29 #include "observable.h"
     30 #include "solib.h"
     31 #include "solib-svr4.h"
     32 #include "solist.h"
     33 #include "symfile.h"
     34 
     35 #include <unordered_map>
     36 
     37 namespace {
     38 
     39 /* Per inferior cache of opened file descriptors.  */
     40 struct rocm_solib_fd_cache
     41 {
     42   explicit rocm_solib_fd_cache (inferior *inf) : m_inferior (inf) {}
     43   DISABLE_COPY_AND_ASSIGN (rocm_solib_fd_cache);
     44 
     45   /* Return a read-only file descriptor to FILENAME and increment the
     46      associated reference count.
     47 
     48      Open the file FILENAME if it is not already opened, reuse the existing file
     49      descriptor otherwise.
     50 
     51      On error -1 is returned, and TARGET_ERRNO is set.  */
     52   int open (const std::string &filename, fileio_error *target_errno);
     53 
     54   /* Decrement the reference count to FD and close FD if the reference count
     55      reaches 0.
     56 
     57      On success, return 0.  On error, return -1 and set TARGET_ERRNO.  */
     58   int close (int fd, fileio_error *target_errno);
     59 
     60 private:
     61   struct refcnt_fd
     62   {
     63     DISABLE_COPY_AND_ASSIGN (refcnt_fd);
     64     refcnt_fd (int fd, int refcnt) : fd (fd), refcnt (refcnt) {}
     65 
     66     int fd = -1;
     67     int refcnt = 0;
     68   };
     69 
     70   inferior *m_inferior;
     71   std::unordered_map<std::string, refcnt_fd> m_cache;
     72 };
     73 
     74 int
     75 rocm_solib_fd_cache::open (const std::string &filename,
     76 			   fileio_error *target_errno)
     77 {
     78   auto it = m_cache.find (filename);
     79   if (it == m_cache.end ())
     80     {
     81       /* The file is not yet opened on the target.  */
     82       int fd
     83 	= target_fileio_open (m_inferior, filename.c_str (), FILEIO_O_RDONLY,
     84 			      false, 0, target_errno);
     85       if (fd != -1)
     86 	m_cache.emplace (std::piecewise_construct,
     87 			 std::forward_as_tuple (filename),
     88 			 std::forward_as_tuple (fd, 1));
     89       return fd;
     90     }
     91   else
     92     {
     93       /* The file is already opened.  Increment the refcnt and return the
     94 	 already opened FD.  */
     95       it->second.refcnt++;
     96       gdb_assert (it->second.fd != -1);
     97       return it->second.fd;
     98     }
     99 }
    100 
    101 int
    102 rocm_solib_fd_cache::close (int fd, fileio_error *target_errno)
    103 {
    104   using cache_val = std::unordered_map<std::string, refcnt_fd>::value_type;
    105   auto it
    106     = std::find_if (m_cache.begin (), m_cache.end (),
    107 		    [fd](const cache_val &s) { return s.second.fd == fd; });
    108 
    109   gdb_assert (it != m_cache.end ());
    110 
    111   it->second.refcnt--;
    112   if (it->second.refcnt == 0)
    113     {
    114       int ret = target_fileio_close (it->second.fd, target_errno);
    115       m_cache.erase (it);
    116       return ret;
    117     }
    118   else
    119     {
    120       /* Keep the FD open for the other users, return success.  */
    121       return 0;
    122     }
    123 }
    124 
    125 } /* Anonymous namespace.  */
    126 
    127 /* ROCm-specific inferior data.  */
    128 
    129 struct rocm_so
    130 {
    131   rocm_so (const char *name, std::string unique_name, lm_info_svr4_up lm_info)
    132     : name (name),
    133       unique_name (std::move (unique_name)),
    134       lm_info (std::move (lm_info))
    135   {}
    136 
    137   std::string name, unique_name;
    138   lm_info_svr4_up lm_info;
    139 };
    140 
    141 struct solib_info
    142 {
    143   explicit solib_info (inferior *inf)
    144     : fd_cache (inf)
    145   {};
    146 
    147   /* List of code objects loaded into the inferior.  */
    148   std::vector<rocm_so> solib_list;
    149 
    150   /* Cache of opened FD in the inferior.  */
    151   rocm_solib_fd_cache fd_cache;
    152 };
    153 
    154 /* Per-inferior data key.  */
    155 static const registry<inferior>::key<solib_info> rocm_solib_data;
    156 
    157 static solib_ops rocm_solib_ops;
    158 
    159 /* Fetch the solib_info data for INF.  */
    160 
    161 static struct solib_info *
    162 get_solib_info (inferior *inf)
    163 {
    164   solib_info *info = rocm_solib_data.get (inf);
    165 
    166   if (info == nullptr)
    167     info = rocm_solib_data.emplace (inf, inf);
    168 
    169   return info;
    170 }
    171 
    172 /* Relocate section addresses.  */
    173 
    174 static void
    175 rocm_solib_relocate_section_addresses (solib &so,
    176 				       struct target_section *sec)
    177 {
    178   if (!is_amdgpu_arch (gdbarch_from_bfd (so.abfd.get ())))
    179     {
    180       svr4_so_ops.relocate_section_addresses (so, sec);
    181       return;
    182     }
    183 
    184   auto *li = gdb::checked_static_cast<lm_info_svr4 *> (so.lm_info.get ());
    185   sec->addr = sec->addr + li->l_addr;
    186   sec->endaddr = sec->endaddr + li->l_addr;
    187 }
    188 
    189 static void rocm_update_solib_list ();
    190 
    191 static void
    192 rocm_solib_handle_event ()
    193 {
    194   /* Since we sit on top of svr4_so_ops, we might get called following an event
    195      concerning host libraries.  We must therefore forward the call.  If the
    196      event was for a ROCm code object, it will be a no-op.  On the other hand,
    197      if the event was for host libraries, rocm_update_solib_list will be
    198      essentially be a no-op (it will reload the same code object list as was
    199      previously loaded).  */
    200   svr4_so_ops.handle_event ();
    201 
    202   rocm_update_solib_list ();
    203 }
    204 
    205 /* Create so_list objects from rocm_so objects in SOS.  */
    206 
    207 static intrusive_list<solib>
    208 so_list_from_rocm_sos (const std::vector<rocm_so> &sos)
    209 {
    210   intrusive_list<solib> dst;
    211 
    212   for (const rocm_so &so : sos)
    213     {
    214       solib *newobj = new solib;
    215       newobj->lm_info = std::make_unique<lm_info_svr4> (*so.lm_info);
    216 
    217       newobj->so_name = so.name;
    218       newobj->so_original_name = so.unique_name;
    219 
    220       dst.push_back (*newobj);
    221     }
    222 
    223   return dst;
    224 }
    225 
    226 /* Build a list of `struct solib' objects describing the shared
    227    objects currently loaded in the inferior.  */
    228 
    229 static intrusive_list<solib>
    230 rocm_solib_current_sos ()
    231 {
    232   /* First, retrieve the host-side shared library list.  */
    233   intrusive_list<solib> sos = svr4_so_ops.current_sos ();
    234 
    235   /* Then, the device-side shared library list.  */
    236   std::vector<rocm_so> &dev_sos = get_solib_info (current_inferior ())->solib_list;
    237 
    238   if (dev_sos.empty ())
    239     return sos;
    240 
    241   intrusive_list<solib> dev_so_list = so_list_from_rocm_sos (dev_sos);
    242 
    243   if (sos.empty ())
    244     return dev_so_list;
    245 
    246   /* Append our libraries to the end of the list.  */
    247   sos.splice (std::move (dev_so_list));
    248 
    249   return sos;
    250 }
    251 
    252 namespace {
    253 
    254 /* Interface to interact with a ROCm code object stream.  */
    255 
    256 struct rocm_code_object_stream : public gdb_bfd_iovec_base
    257 {
    258   DISABLE_COPY_AND_ASSIGN (rocm_code_object_stream);
    259 
    260   int stat (bfd *abfd, struct stat *sb) final override;
    261 
    262   ~rocm_code_object_stream () override = default;
    263 
    264 protected:
    265   rocm_code_object_stream () = default;
    266 
    267   /* Return the size of the object file, or -1 if the size cannot be
    268      determined.
    269 
    270      This is a helper function for stat.  */
    271   virtual LONGEST size () = 0;
    272 };
    273 
    274 int
    275 rocm_code_object_stream::stat (bfd *, struct stat *sb)
    276 {
    277   const LONGEST size = this->size ();
    278   if (size == -1)
    279     return -1;
    280 
    281   memset (sb, '\0', sizeof (struct stat));
    282   sb->st_size = size;
    283   return 0;
    284 }
    285 
    286 /* Interface to a ROCm object stream which is embedded in an ELF file
    287    accessible to the debugger.  */
    288 
    289 struct rocm_code_object_stream_file final : rocm_code_object_stream
    290 {
    291   DISABLE_COPY_AND_ASSIGN (rocm_code_object_stream_file);
    292 
    293   rocm_code_object_stream_file (inferior *inf, int fd, ULONGEST offset,
    294 				ULONGEST size);
    295 
    296   file_ptr read (bfd *abfd, void *buf, file_ptr size,
    297 		 file_ptr offset) override;
    298 
    299   LONGEST size () override;
    300 
    301   ~rocm_code_object_stream_file () override;
    302 
    303 protected:
    304 
    305   /* The inferior owning this code object stream.  */
    306   inferior *m_inf;
    307 
    308   /* The target file descriptor for this stream.  */
    309   int m_fd;
    310 
    311   /* The offset of the ELF file image in the target file.  */
    312   ULONGEST m_offset;
    313 
    314   /* The size of the ELF file image.  The value 0 means that it was
    315      unspecified in the URI descriptor.  */
    316   ULONGEST m_size;
    317 };
    318 
    319 rocm_code_object_stream_file::rocm_code_object_stream_file
    320   (inferior *inf, int fd, ULONGEST offset, ULONGEST size)
    321   : m_inf (inf), m_fd (fd), m_offset (offset), m_size (size)
    322 {
    323 }
    324 
    325 file_ptr
    326 rocm_code_object_stream_file::read (bfd *, void *buf, file_ptr size,
    327 				    file_ptr offset)
    328 {
    329   fileio_error target_errno;
    330   file_ptr nbytes = 0;
    331   while (size > 0)
    332     {
    333       QUIT;
    334 
    335       file_ptr bytes_read
    336 	= target_fileio_pread (m_fd, static_cast<gdb_byte *> (buf) + nbytes,
    337 			       size, m_offset + offset + nbytes,
    338 			       &target_errno);
    339 
    340       if (bytes_read == 0)
    341 	break;
    342 
    343       if (bytes_read < 0)
    344 	{
    345 	  errno = fileio_error_to_host (target_errno);
    346 	  bfd_set_error (bfd_error_system_call);
    347 	  return -1;
    348 	}
    349 
    350       nbytes += bytes_read;
    351       size -= bytes_read;
    352     }
    353 
    354   return nbytes;
    355 }
    356 
    357 LONGEST
    358 rocm_code_object_stream_file::size ()
    359 {
    360   if (m_size == 0)
    361     {
    362       fileio_error target_errno;
    363       struct stat stat;
    364       if (target_fileio_fstat (m_fd, &stat, &target_errno) < 0)
    365 	{
    366 	  errno = fileio_error_to_host (target_errno);
    367 	  bfd_set_error (bfd_error_system_call);
    368 	  return -1;
    369 	}
    370 
    371       /* Check that the offset is valid.  */
    372       if (m_offset >= stat.st_size)
    373 	{
    374 	  bfd_set_error (bfd_error_bad_value);
    375 	  return -1;
    376 	}
    377 
    378       m_size = stat.st_size - m_offset;
    379     }
    380 
    381   return m_size;
    382 }
    383 
    384 rocm_code_object_stream_file::~rocm_code_object_stream_file ()
    385 {
    386   auto info = get_solib_info (m_inf);
    387   fileio_error target_errno;
    388   if (info->fd_cache.close (m_fd, &target_errno) != 0)
    389     warning (_("Failed to close solib: %s"),
    390 	     strerror (fileio_error_to_host (target_errno)));
    391 }
    392 
    393 /* Interface to a code object which lives in the inferior's memory.  */
    394 
    395 struct rocm_code_object_stream_memory final : public rocm_code_object_stream
    396 {
    397   DISABLE_COPY_AND_ASSIGN (rocm_code_object_stream_memory);
    398 
    399   rocm_code_object_stream_memory (gdb::byte_vector buffer);
    400 
    401   file_ptr read (bfd *abfd, void *buf, file_ptr size,
    402 		 file_ptr offset) override;
    403 
    404 protected:
    405 
    406   /* Snapshot of the original ELF image taken during load.  This is done to
    407      support the situation where an inferior uses an in-memory image, and
    408      releases or re-uses this memory before GDB is done using it.  */
    409   gdb::byte_vector m_objfile_image;
    410 
    411   LONGEST size () override
    412   {
    413     return m_objfile_image.size ();
    414   }
    415 };
    416 
    417 rocm_code_object_stream_memory::rocm_code_object_stream_memory
    418   (gdb::byte_vector buffer)
    419   : m_objfile_image (std::move (buffer))
    420 {
    421 }
    422 
    423 file_ptr
    424 rocm_code_object_stream_memory::read (bfd *, void *buf, file_ptr size,
    425 				      file_ptr offset)
    426 {
    427   if (size > m_objfile_image.size () - offset)
    428     size = m_objfile_image.size () - offset;
    429 
    430   memcpy (buf, m_objfile_image.data () + offset, size);
    431   return size;
    432 }
    433 
    434 } /* anonymous namespace */
    435 
    436 static gdb_bfd_iovec_base *
    437 rocm_bfd_iovec_open (bfd *abfd, inferior *inferior)
    438 {
    439   std::string_view uri (bfd_get_filename (abfd));
    440   std::string_view protocol_delim = "://";
    441   size_t protocol_end = uri.find (protocol_delim);
    442   std::string protocol (uri.substr (0, protocol_end));
    443   protocol_end += protocol_delim.length ();
    444 
    445   std::transform (protocol.begin (), protocol.end (), protocol.begin (),
    446 		  [] (unsigned char c) { return std::tolower (c); });
    447 
    448   std::string_view path;
    449   size_t path_end = uri.find_first_of ("#?", protocol_end);
    450   if (path_end != std::string::npos)
    451     path = uri.substr (protocol_end, path_end++ - protocol_end);
    452   else
    453     path = uri.substr (protocol_end);
    454 
    455   /* %-decode the string.  */
    456   std::string decoded_path;
    457   decoded_path.reserve (path.length ());
    458   for (size_t i = 0; i < path.length (); ++i)
    459     if (path[i] == '%'
    460 	&& i < path.length () - 2
    461 	&& std::isxdigit ((unsigned char)path[i + 1])
    462 	&& std::isxdigit ((unsigned char)path[i + 2]))
    463       {
    464 	std::string_view hex_digits = path.substr (i + 1, 2);
    465 	decoded_path += std::stoi (std::string (hex_digits), 0, 16);
    466 	i += 2;
    467       }
    468     else
    469       decoded_path += path[i];
    470 
    471   /* Tokenize the query/fragment.  */
    472   std::vector<std::string_view> tokens;
    473   size_t pos, last = path_end;
    474   while ((pos = uri.find ('&', last)) != std::string::npos)
    475     {
    476       tokens.emplace_back (uri.substr (last, pos - last));
    477       last = pos + 1;
    478     }
    479 
    480   if (last != std::string::npos)
    481     tokens.emplace_back (uri.substr (last));
    482 
    483   /* Create a tag-value map from the tokenized query/fragment.  */
    484   std::unordered_map<std::string_view, std::string_view,
    485 		     gdb::string_view_hash> params;
    486   for (std::string_view token : tokens)
    487     {
    488       size_t delim = token.find ('=');
    489       if (delim != std::string::npos)
    490 	{
    491 	  std::string_view tag = token.substr (0, delim);
    492 	  std::string_view val = token.substr (delim + 1);
    493 	  params.emplace (tag, val);
    494 	}
    495     }
    496 
    497   try
    498     {
    499       ULONGEST offset = 0;
    500       ULONGEST size = 0;
    501 
    502       auto try_strtoulst = [] (std::string_view v)
    503 	{
    504 	  errno = 0;
    505 	  ULONGEST value = strtoulst (v.data (), nullptr, 0);
    506 	  if (errno != 0)
    507 	    {
    508 	      /* The actual message doesn't matter, the exception is caught
    509 		 below, transformed in a BFD error, and the message is lost.  */
    510 	      error (_("Failed to parse integer."));
    511 	    }
    512 
    513 	  return value;
    514 	};
    515 
    516       auto offset_it = params.find ("offset");
    517       if (offset_it != params.end ())
    518 	offset = try_strtoulst (offset_it->second);
    519 
    520       auto size_it = params.find ("size");
    521       if (size_it != params.end ())
    522 	{
    523 	  size = try_strtoulst (size_it->second);
    524 	  if (size == 0)
    525 	    error (_("Invalid size value"));
    526 	}
    527 
    528       if (protocol == "file")
    529 	{
    530 	  auto info = get_solib_info (inferior);
    531 	  fileio_error target_errno;
    532 	  int fd = info->fd_cache.open (decoded_path, &target_errno);
    533 
    534 	  if (fd == -1)
    535 	    {
    536 	      errno = fileio_error_to_host (target_errno);
    537 	      bfd_set_error (bfd_error_system_call);
    538 	      return nullptr;
    539 	    }
    540 
    541 	  return new rocm_code_object_stream_file (inferior, fd, offset,
    542 						   size);
    543 	}
    544 
    545       if (protocol == "memory")
    546 	{
    547 	  ULONGEST pid = try_strtoulst (path);
    548 	  if (pid != inferior->pid)
    549 	    {
    550 	      warning (_("`%s': code object is from another inferior"),
    551 		       std::string (uri).c_str ());
    552 	      bfd_set_error (bfd_error_bad_value);
    553 	      return nullptr;
    554 	    }
    555 
    556 	  gdb::byte_vector buffer (size);
    557 	  if (target_read_memory (offset, buffer.data (), size) != 0)
    558 	    {
    559 	      warning (_("Failed to copy the code object from the inferior"));
    560 	      bfd_set_error (bfd_error_bad_value);
    561 	      return nullptr;
    562 	    }
    563 
    564 	  return new rocm_code_object_stream_memory (std::move (buffer));
    565 	}
    566 
    567       warning (_("`%s': protocol not supported: %s"),
    568 	       std::string (uri).c_str (), protocol.c_str ());
    569       bfd_set_error (bfd_error_bad_value);
    570       return nullptr;
    571     }
    572   catch (const gdb_exception_quit &ex)
    573     {
    574       set_quit_flag ();
    575       bfd_set_error (bfd_error_bad_value);
    576       return nullptr;
    577     }
    578   catch (const gdb_exception &ex)
    579     {
    580       bfd_set_error (bfd_error_bad_value);
    581       return nullptr;
    582     }
    583 }
    584 
    585 static gdb_bfd_ref_ptr
    586 rocm_solib_bfd_open (const char *pathname)
    587 {
    588   /* Handle regular files with SVR4 open.  */
    589   if (strstr (pathname, "://") == nullptr)
    590     return svr4_so_ops.bfd_open (pathname);
    591 
    592   auto open = [] (bfd *nbfd) -> gdb_bfd_iovec_base *
    593   {
    594     return rocm_bfd_iovec_open (nbfd, current_inferior ());
    595   };
    596 
    597   gdb_bfd_ref_ptr abfd = gdb_bfd_openr_iovec (pathname, "elf64-amdgcn", open);
    598 
    599   if (abfd == nullptr)
    600     error (_("Could not open `%s' as an executable file: %s"), pathname,
    601 	   bfd_errmsg (bfd_get_error ()));
    602 
    603   /* Check bfd format.  */
    604   if (!bfd_check_format (abfd.get (), bfd_object))
    605     error (_("`%s': not in executable format: %s"),
    606 	   bfd_get_filename (abfd.get ()), bfd_errmsg (bfd_get_error ()));
    607 
    608   unsigned char osabi = elf_elfheader (abfd)->e_ident[EI_OSABI];
    609   unsigned char osabiversion = elf_elfheader (abfd)->e_ident[EI_ABIVERSION];
    610 
    611   /* Check that the code object is using the HSA OS ABI.  */
    612   if (osabi != ELFOSABI_AMDGPU_HSA)
    613     error (_("`%s': ELF file OS ABI is not supported (%d)."),
    614 	   bfd_get_filename (abfd.get ()), osabi);
    615 
    616   /* We support HSA code objects V3 and greater.  */
    617   if (osabiversion < ELFABIVERSION_AMDGPU_HSA_V3)
    618     error (_("`%s': ELF file HSA OS ABI version is not supported (%d)."),
    619 	   bfd_get_filename (abfd.get ()), osabiversion);
    620 
    621   /* For GDB to be able to use this solib, the exact AMDGPU processor type
    622      must be supported by both BFD and the amd-dbgapi library.  */
    623   const unsigned char gfx_arch
    624     = elf_elfheader (abfd)->e_flags & EF_AMDGPU_MACH ;
    625   const bfd_arch_info_type *bfd_arch_info
    626     = bfd_lookup_arch (bfd_arch_amdgcn, gfx_arch);
    627 
    628   amd_dbgapi_architecture_id_t architecture_id;
    629   amd_dbgapi_status_t dbgapi_query_arch
    630     = amd_dbgapi_get_architecture (gfx_arch, &architecture_id);
    631 
    632   if (dbgapi_query_arch != AMD_DBGAPI_STATUS_SUCCESS
    633       || bfd_arch_info ==  nullptr)
    634     {
    635       if (dbgapi_query_arch != AMD_DBGAPI_STATUS_SUCCESS
    636 	  && bfd_arch_info ==  nullptr)
    637 	{
    638 	  /* Neither of the libraries knows about this arch, so we cannot
    639 	     provide a human readable name for it.  */
    640 	  error (_("'%s': AMDGCN architecture %#02x is not supported."),
    641 		 bfd_get_filename (abfd.get ()), gfx_arch);
    642 	}
    643       else if (dbgapi_query_arch != AMD_DBGAPI_STATUS_SUCCESS)
    644 	{
    645 	  gdb_assert (bfd_arch_info != nullptr);
    646 	  error (_("'%s': AMDGCN architecture %s not supported by "
    647 		   "amd-dbgapi."),
    648 		 bfd_get_filename (abfd.get ()),
    649 		 bfd_arch_info->printable_name);
    650 	}
    651       else
    652 	{
    653 	  gdb_assert (dbgapi_query_arch == AMD_DBGAPI_STATUS_SUCCESS);
    654 	  char *arch_name;
    655 	  if (amd_dbgapi_architecture_get_info
    656 	      (architecture_id, AMD_DBGAPI_ARCHITECTURE_INFO_NAME,
    657 	       sizeof (arch_name), &arch_name) != AMD_DBGAPI_STATUS_SUCCESS)
    658 	    error ("amd_dbgapi_architecture_get_info call failed for arch "
    659 		   "%#02x.", gfx_arch);
    660 	  gdb::unique_xmalloc_ptr<char> arch_name_cleaner (arch_name);
    661 
    662 	  error (_("'%s': AMDGCN architecture %s not supported."),
    663 		 bfd_get_filename (abfd.get ()),
    664 		 arch_name);
    665 	}
    666     }
    667 
    668   gdb_assert (gdbarch_from_bfd (abfd.get ()) != nullptr);
    669   gdb_assert (is_amdgpu_arch (gdbarch_from_bfd (abfd.get ())));
    670 
    671   return abfd;
    672 }
    673 
    674 static void
    675 rocm_solib_create_inferior_hook (int from_tty)
    676 {
    677   get_solib_info (current_inferior ())->solib_list.clear ();
    678 
    679   svr4_so_ops.solib_create_inferior_hook (from_tty);
    680 }
    681 
    682 static void
    683 rocm_update_solib_list ()
    684 {
    685   inferior *inf = current_inferior ();
    686 
    687   amd_dbgapi_process_id_t process_id = get_amd_dbgapi_process_id (inf);
    688   if (process_id.handle == AMD_DBGAPI_PROCESS_NONE.handle)
    689     return;
    690 
    691   solib_info *info = get_solib_info (inf);
    692 
    693   info->solib_list.clear ();
    694   std::vector<rocm_so> &sos = info->solib_list;
    695 
    696   amd_dbgapi_code_object_id_t *code_object_list;
    697   size_t count;
    698 
    699   amd_dbgapi_status_t status
    700     = amd_dbgapi_process_code_object_list (process_id, &count,
    701 					   &code_object_list, nullptr);
    702   if (status != AMD_DBGAPI_STATUS_SUCCESS)
    703     {
    704       warning (_("amd_dbgapi_process_code_object_list failed (%s)"),
    705 	       get_status_string (status));
    706       return;
    707     }
    708 
    709   for (size_t i = 0; i < count; ++i)
    710     {
    711       CORE_ADDR l_addr;
    712       char *uri_bytes;
    713 
    714       status = amd_dbgapi_code_object_get_info
    715 	(code_object_list[i], AMD_DBGAPI_CODE_OBJECT_INFO_LOAD_ADDRESS,
    716 	 sizeof (l_addr), &l_addr);
    717       if (status != AMD_DBGAPI_STATUS_SUCCESS)
    718 	continue;
    719 
    720       status = amd_dbgapi_code_object_get_info
    721 	(code_object_list[i], AMD_DBGAPI_CODE_OBJECT_INFO_URI_NAME,
    722 	 sizeof (uri_bytes), &uri_bytes);
    723       if (status != AMD_DBGAPI_STATUS_SUCCESS)
    724 	continue;
    725 
    726       gdb::unique_xmalloc_ptr<char> uri_bytes_holder (uri_bytes);
    727 
    728       lm_info_svr4_up li = std::make_unique<lm_info_svr4> ();
    729       li->l_addr = l_addr;
    730 
    731       /* Generate a unique name so that code objects with the same URI but
    732 	 different load addresses are seen by gdb core as different shared
    733 	 objects.  */
    734       std::string unique_name
    735 	= string_printf ("code_object_%ld", code_object_list[i].handle);
    736 
    737       sos.emplace_back (uri_bytes, std::move (unique_name), std::move (li));
    738     }
    739 
    740   xfree (code_object_list);
    741 
    742   if (rocm_solib_ops.current_sos == NULL)
    743     {
    744       /* Override what we need to.  */
    745       rocm_solib_ops = svr4_so_ops;
    746       rocm_solib_ops.current_sos = rocm_solib_current_sos;
    747       rocm_solib_ops.solib_create_inferior_hook
    748 	= rocm_solib_create_inferior_hook;
    749       rocm_solib_ops.bfd_open = rocm_solib_bfd_open;
    750       rocm_solib_ops.relocate_section_addresses
    751 	= rocm_solib_relocate_section_addresses;
    752       rocm_solib_ops.handle_event = rocm_solib_handle_event;
    753 
    754       /* Engage the ROCm so_ops.  */
    755       set_gdbarch_so_ops (current_inferior ()->arch (), &rocm_solib_ops);
    756     }
    757 }
    758 
    759 static void
    760 rocm_solib_target_inferior_created (inferior *inf)
    761 {
    762   get_solib_info (inf)->solib_list.clear ();
    763 
    764   rocm_update_solib_list ();
    765 
    766   /* Force GDB to reload the solibs.  */
    767   current_inferior ()->pspace->clear_solib_cache ();
    768   solib_add (nullptr, 0, auto_solib_add);
    769 }
    770 
    771 /* -Wmissing-prototypes */
    772 extern initialize_file_ftype _initialize_rocm_solib;
    773 
    774 void
    775 _initialize_rocm_solib ()
    776 {
    777   /* The dependency on the amd-dbgapi exists because solib-rocm's
    778      inferior_created observer needs amd-dbgapi to have attached the process,
    779      which happens in amd_dbgapi_target's inferior_created observer.  */
    780   gdb::observers::inferior_created.attach
    781     (rocm_solib_target_inferior_created,
    782      "solib-rocm",
    783      { &get_amd_dbgapi_target_inferior_created_observer_token () });
    784 }
    785