Home | History | Annotate | Line # | Download | only in gdb
solib-rocm.c revision 1.1.1.2
      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 owning_intrusive_list<solib>
    208 so_list_from_rocm_sos (const std::vector<rocm_so> &sos)
    209 {
    210   owning_intrusive_list<solib> dst;
    211 
    212   for (const rocm_so &so : sos)
    213     {
    214       auto &newobj = dst.emplace_back ();
    215 
    216       newobj.lm_info = std::make_unique<lm_info_svr4> (*so.lm_info);
    217       newobj.so_name = so.name;
    218       newobj.so_original_name = so.unique_name;
    219     }
    220 
    221   return dst;
    222 }
    223 
    224 /* Build a list of `struct solib' objects describing the shared
    225    objects currently loaded in the inferior.  */
    226 
    227 static owning_intrusive_list<solib>
    228 rocm_solib_current_sos ()
    229 {
    230   /* First, retrieve the host-side shared library list.  */
    231   owning_intrusive_list<solib> sos = svr4_so_ops.current_sos ();
    232 
    233   /* Then, the device-side shared library list.  */
    234   std::vector<rocm_so> &dev_sos = get_solib_info (current_inferior ())->solib_list;
    235 
    236   if (dev_sos.empty ())
    237     return sos;
    238 
    239   owning_intrusive_list<solib> dev_so_list = so_list_from_rocm_sos (dev_sos);
    240 
    241   if (sos.empty ())
    242     return dev_so_list;
    243 
    244   /* Append our libraries to the end of the list.  */
    245   sos.splice (std::move (dev_so_list));
    246 
    247   return sos;
    248 }
    249 
    250 namespace {
    251 
    252 /* Interface to interact with a ROCm code object stream.  */
    253 
    254 struct rocm_code_object_stream : public gdb_bfd_iovec_base
    255 {
    256   DISABLE_COPY_AND_ASSIGN (rocm_code_object_stream);
    257 
    258   int stat (bfd *abfd, struct stat *sb) final override;
    259 
    260   ~rocm_code_object_stream () override = default;
    261 
    262 protected:
    263   rocm_code_object_stream () = default;
    264 
    265   /* Return the size of the object file, or -1 if the size cannot be
    266      determined.
    267 
    268      This is a helper function for stat.  */
    269   virtual LONGEST size () = 0;
    270 };
    271 
    272 int
    273 rocm_code_object_stream::stat (bfd *, struct stat *sb)
    274 {
    275   const LONGEST size = this->size ();
    276   if (size == -1)
    277     return -1;
    278 
    279   memset (sb, '\0', sizeof (struct stat));
    280   sb->st_size = size;
    281   return 0;
    282 }
    283 
    284 /* Interface to a ROCm object stream which is embedded in an ELF file
    285    accessible to the debugger.  */
    286 
    287 struct rocm_code_object_stream_file final : rocm_code_object_stream
    288 {
    289   DISABLE_COPY_AND_ASSIGN (rocm_code_object_stream_file);
    290 
    291   rocm_code_object_stream_file (inferior *inf, int fd, ULONGEST offset,
    292 				ULONGEST size);
    293 
    294   file_ptr read (bfd *abfd, void *buf, file_ptr size,
    295 		 file_ptr offset) override;
    296 
    297   LONGEST size () override;
    298 
    299   ~rocm_code_object_stream_file () override;
    300 
    301 protected:
    302 
    303   /* The inferior owning this code object stream.  */
    304   inferior *m_inf;
    305 
    306   /* The target file descriptor for this stream.  */
    307   int m_fd;
    308 
    309   /* The offset of the ELF file image in the target file.  */
    310   ULONGEST m_offset;
    311 
    312   /* The size of the ELF file image.  The value 0 means that it was
    313      unspecified in the URI descriptor.  */
    314   ULONGEST m_size;
    315 };
    316 
    317 rocm_code_object_stream_file::rocm_code_object_stream_file
    318   (inferior *inf, int fd, ULONGEST offset, ULONGEST size)
    319   : m_inf (inf), m_fd (fd), m_offset (offset), m_size (size)
    320 {
    321 }
    322 
    323 file_ptr
    324 rocm_code_object_stream_file::read (bfd *, void *buf, file_ptr size,
    325 				    file_ptr offset)
    326 {
    327   fileio_error target_errno;
    328   file_ptr nbytes = 0;
    329   while (size > 0)
    330     {
    331       QUIT;
    332 
    333       file_ptr bytes_read
    334 	= target_fileio_pread (m_fd, static_cast<gdb_byte *> (buf) + nbytes,
    335 			       size, m_offset + offset + nbytes,
    336 			       &target_errno);
    337 
    338       if (bytes_read == 0)
    339 	break;
    340 
    341       if (bytes_read < 0)
    342 	{
    343 	  errno = fileio_error_to_host (target_errno);
    344 	  bfd_set_error (bfd_error_system_call);
    345 	  return -1;
    346 	}
    347 
    348       nbytes += bytes_read;
    349       size -= bytes_read;
    350     }
    351 
    352   return nbytes;
    353 }
    354 
    355 LONGEST
    356 rocm_code_object_stream_file::size ()
    357 {
    358   if (m_size == 0)
    359     {
    360       fileio_error target_errno;
    361       struct stat stat;
    362       if (target_fileio_fstat (m_fd, &stat, &target_errno) < 0)
    363 	{
    364 	  errno = fileio_error_to_host (target_errno);
    365 	  bfd_set_error (bfd_error_system_call);
    366 	  return -1;
    367 	}
    368 
    369       /* Check that the offset is valid.  */
    370       if (m_offset >= stat.st_size)
    371 	{
    372 	  bfd_set_error (bfd_error_bad_value);
    373 	  return -1;
    374 	}
    375 
    376       m_size = stat.st_size - m_offset;
    377     }
    378 
    379   return m_size;
    380 }
    381 
    382 rocm_code_object_stream_file::~rocm_code_object_stream_file ()
    383 {
    384   auto info = get_solib_info (m_inf);
    385   fileio_error target_errno;
    386   if (info->fd_cache.close (m_fd, &target_errno) != 0)
    387     warning (_("Failed to close solib: %s"),
    388 	     strerror (fileio_error_to_host (target_errno)));
    389 }
    390 
    391 /* Interface to a code object which lives in the inferior's memory.  */
    392 
    393 struct rocm_code_object_stream_memory final : public rocm_code_object_stream
    394 {
    395   DISABLE_COPY_AND_ASSIGN (rocm_code_object_stream_memory);
    396 
    397   rocm_code_object_stream_memory (gdb::byte_vector buffer);
    398 
    399   file_ptr read (bfd *abfd, void *buf, file_ptr size,
    400 		 file_ptr offset) override;
    401 
    402 protected:
    403 
    404   /* Snapshot of the original ELF image taken during load.  This is done to
    405      support the situation where an inferior uses an in-memory image, and
    406      releases or re-uses this memory before GDB is done using it.  */
    407   gdb::byte_vector m_objfile_image;
    408 
    409   LONGEST size () override
    410   {
    411     return m_objfile_image.size ();
    412   }
    413 };
    414 
    415 rocm_code_object_stream_memory::rocm_code_object_stream_memory
    416   (gdb::byte_vector buffer)
    417   : m_objfile_image (std::move (buffer))
    418 {
    419 }
    420 
    421 file_ptr
    422 rocm_code_object_stream_memory::read (bfd *, void *buf, file_ptr size,
    423 				      file_ptr offset)
    424 {
    425   if (size > m_objfile_image.size () - offset)
    426     size = m_objfile_image.size () - offset;
    427 
    428   memcpy (buf, m_objfile_image.data () + offset, size);
    429   return size;
    430 }
    431 
    432 } /* anonymous namespace */
    433 
    434 static gdb_bfd_iovec_base *
    435 rocm_bfd_iovec_open (bfd *abfd, inferior *inferior)
    436 {
    437   std::string_view uri (bfd_get_filename (abfd));
    438   std::string_view protocol_delim = "://";
    439   size_t protocol_end = uri.find (protocol_delim);
    440   std::string protocol (uri.substr (0, protocol_end));
    441   protocol_end += protocol_delim.length ();
    442 
    443   std::transform (protocol.begin (), protocol.end (), protocol.begin (),
    444 		  [] (unsigned char c) { return std::tolower (c); });
    445 
    446   std::string_view path;
    447   size_t path_end = uri.find_first_of ("#?", protocol_end);
    448   if (path_end != std::string::npos)
    449     path = uri.substr (protocol_end, path_end++ - protocol_end);
    450   else
    451     path = uri.substr (protocol_end);
    452 
    453   /* %-decode the string.  */
    454   std::string decoded_path;
    455   decoded_path.reserve (path.length ());
    456   for (size_t i = 0; i < path.length (); ++i)
    457     if (path[i] == '%'
    458 	&& i < path.length () - 2
    459 	&& std::isxdigit ((unsigned char)path[i + 1])
    460 	&& std::isxdigit ((unsigned char)path[i + 2]))
    461       {
    462 	std::string_view hex_digits = path.substr (i + 1, 2);
    463 	decoded_path += std::stoi (std::string (hex_digits), 0, 16);
    464 	i += 2;
    465       }
    466     else
    467       decoded_path += path[i];
    468 
    469   /* Tokenize the query/fragment.  */
    470   std::vector<std::string_view> tokens;
    471   size_t pos, last = path_end;
    472   while ((pos = uri.find ('&', last)) != std::string::npos)
    473     {
    474       tokens.emplace_back (uri.substr (last, pos - last));
    475       last = pos + 1;
    476     }
    477 
    478   if (last != std::string::npos)
    479     tokens.emplace_back (uri.substr (last));
    480 
    481   /* Create a tag-value map from the tokenized query/fragment.  */
    482   std::unordered_map<std::string_view, std::string_view,
    483 		     gdb::string_view_hash> params;
    484   for (std::string_view token : tokens)
    485     {
    486       size_t delim = token.find ('=');
    487       if (delim != std::string::npos)
    488 	{
    489 	  std::string_view tag = token.substr (0, delim);
    490 	  std::string_view val = token.substr (delim + 1);
    491 	  params.emplace (tag, val);
    492 	}
    493     }
    494 
    495   try
    496     {
    497       ULONGEST offset = 0;
    498       ULONGEST size = 0;
    499 
    500       auto try_strtoulst = [] (std::string_view v)
    501 	{
    502 	  errno = 0;
    503 	  ULONGEST value = strtoulst (v.data (), nullptr, 0);
    504 	  if (errno != 0)
    505 	    {
    506 	      /* The actual message doesn't matter, the exception is caught
    507 		 below, transformed in a BFD error, and the message is lost.  */
    508 	      error (_("Failed to parse integer."));
    509 	    }
    510 
    511 	  return value;
    512 	};
    513 
    514       auto offset_it = params.find ("offset");
    515       if (offset_it != params.end ())
    516 	offset = try_strtoulst (offset_it->second);
    517 
    518       auto size_it = params.find ("size");
    519       if (size_it != params.end ())
    520 	{
    521 	  size = try_strtoulst (size_it->second);
    522 	  if (size == 0)
    523 	    error (_("Invalid size value"));
    524 	}
    525 
    526       if (protocol == "file")
    527 	{
    528 	  auto info = get_solib_info (inferior);
    529 	  fileio_error target_errno;
    530 	  int fd = info->fd_cache.open (decoded_path, &target_errno);
    531 
    532 	  if (fd == -1)
    533 	    {
    534 	      errno = fileio_error_to_host (target_errno);
    535 	      bfd_set_error (bfd_error_system_call);
    536 	      return nullptr;
    537 	    }
    538 
    539 	  return new rocm_code_object_stream_file (inferior, fd, offset,
    540 						   size);
    541 	}
    542 
    543       if (protocol == "memory")
    544 	{
    545 	  ULONGEST pid = try_strtoulst (path);
    546 	  if (pid != inferior->pid)
    547 	    {
    548 	      warning (_("`%s': code object is from another inferior"),
    549 		       std::string (uri).c_str ());
    550 	      bfd_set_error (bfd_error_bad_value);
    551 	      return nullptr;
    552 	    }
    553 
    554 	  gdb::byte_vector buffer (size);
    555 	  if (target_read_memory (offset, buffer.data (), size) != 0)
    556 	    {
    557 	      warning (_("Failed to copy the code object from the inferior"));
    558 	      bfd_set_error (bfd_error_bad_value);
    559 	      return nullptr;
    560 	    }
    561 
    562 	  return new rocm_code_object_stream_memory (std::move (buffer));
    563 	}
    564 
    565       warning (_("`%s': protocol not supported: %s"),
    566 	       std::string (uri).c_str (), protocol.c_str ());
    567       bfd_set_error (bfd_error_bad_value);
    568       return nullptr;
    569     }
    570   catch (const gdb_exception_quit &ex)
    571     {
    572       set_quit_flag ();
    573       bfd_set_error (bfd_error_bad_value);
    574       return nullptr;
    575     }
    576   catch (const gdb_exception &ex)
    577     {
    578       bfd_set_error (bfd_error_bad_value);
    579       return nullptr;
    580     }
    581 }
    582 
    583 static gdb_bfd_ref_ptr
    584 rocm_solib_bfd_open (const char *pathname)
    585 {
    586   /* Handle regular files with SVR4 open.  */
    587   if (strstr (pathname, "://") == nullptr)
    588     return svr4_so_ops.bfd_open (pathname);
    589 
    590   auto open = [] (bfd *nbfd) -> gdb_bfd_iovec_base *
    591   {
    592     return rocm_bfd_iovec_open (nbfd, current_inferior ());
    593   };
    594 
    595   gdb_bfd_ref_ptr abfd = gdb_bfd_openr_iovec (pathname, "elf64-amdgcn", open);
    596 
    597   if (abfd == nullptr)
    598     error (_("Could not open `%s' as an executable file: %s"), pathname,
    599 	   bfd_errmsg (bfd_get_error ()));
    600 
    601   /* Check bfd format.  */
    602   if (!bfd_check_format (abfd.get (), bfd_object))
    603     error (_("`%s': not in executable format: %s"),
    604 	   bfd_get_filename (abfd.get ()), bfd_errmsg (bfd_get_error ()));
    605 
    606   unsigned char osabi = elf_elfheader (abfd)->e_ident[EI_OSABI];
    607   unsigned char osabiversion = elf_elfheader (abfd)->e_ident[EI_ABIVERSION];
    608 
    609   /* Check that the code object is using the HSA OS ABI.  */
    610   if (osabi != ELFOSABI_AMDGPU_HSA)
    611     error (_("`%s': ELF file OS ABI is not supported (%d)."),
    612 	   bfd_get_filename (abfd.get ()), osabi);
    613 
    614   /* We support HSA code objects V3 and greater.  */
    615   if (osabiversion < ELFABIVERSION_AMDGPU_HSA_V3)
    616     error (_("`%s': ELF file HSA OS ABI version is not supported (%d)."),
    617 	   bfd_get_filename (abfd.get ()), osabiversion);
    618 
    619   /* For GDB to be able to use this solib, the exact AMDGPU processor type
    620      must be supported by both BFD and the amd-dbgapi library.  */
    621   const unsigned char gfx_arch
    622     = elf_elfheader (abfd)->e_flags & EF_AMDGPU_MACH ;
    623   const bfd_arch_info_type *bfd_arch_info
    624     = bfd_lookup_arch (bfd_arch_amdgcn, gfx_arch);
    625 
    626   amd_dbgapi_architecture_id_t architecture_id;
    627   amd_dbgapi_status_t dbgapi_query_arch
    628     = amd_dbgapi_get_architecture (gfx_arch, &architecture_id);
    629 
    630   if (dbgapi_query_arch != AMD_DBGAPI_STATUS_SUCCESS
    631       || bfd_arch_info ==  nullptr)
    632     {
    633       if (dbgapi_query_arch != AMD_DBGAPI_STATUS_SUCCESS
    634 	  && bfd_arch_info ==  nullptr)
    635 	{
    636 	  /* Neither of the libraries knows about this arch, so we cannot
    637 	     provide a human readable name for it.  */
    638 	  error (_("'%s': AMDGCN architecture %#02x is not supported."),
    639 		 bfd_get_filename (abfd.get ()), gfx_arch);
    640 	}
    641       else if (dbgapi_query_arch != AMD_DBGAPI_STATUS_SUCCESS)
    642 	{
    643 	  gdb_assert (bfd_arch_info != nullptr);
    644 	  error (_("'%s': AMDGCN architecture %s not supported by "
    645 		   "amd-dbgapi."),
    646 		 bfd_get_filename (abfd.get ()),
    647 		 bfd_arch_info->printable_name);
    648 	}
    649       else
    650 	{
    651 	  gdb_assert (dbgapi_query_arch == AMD_DBGAPI_STATUS_SUCCESS);
    652 	  char *arch_name;
    653 	  if (amd_dbgapi_architecture_get_info
    654 	      (architecture_id, AMD_DBGAPI_ARCHITECTURE_INFO_NAME,
    655 	       sizeof (arch_name), &arch_name) != AMD_DBGAPI_STATUS_SUCCESS)
    656 	    error ("amd_dbgapi_architecture_get_info call failed for arch "
    657 		   "%#02x.", gfx_arch);
    658 	  gdb::unique_xmalloc_ptr<char> arch_name_cleaner (arch_name);
    659 
    660 	  error (_("'%s': AMDGCN architecture %s not supported."),
    661 		 bfd_get_filename (abfd.get ()),
    662 		 arch_name);
    663 	}
    664     }
    665 
    666   gdb_assert (gdbarch_from_bfd (abfd.get ()) != nullptr);
    667   gdb_assert (is_amdgpu_arch (gdbarch_from_bfd (abfd.get ())));
    668 
    669   return abfd;
    670 }
    671 
    672 static void
    673 rocm_solib_create_inferior_hook (int from_tty)
    674 {
    675   get_solib_info (current_inferior ())->solib_list.clear ();
    676 
    677   svr4_so_ops.solib_create_inferior_hook (from_tty);
    678 }
    679 
    680 static void
    681 rocm_update_solib_list ()
    682 {
    683   inferior *inf = current_inferior ();
    684 
    685   amd_dbgapi_process_id_t process_id = get_amd_dbgapi_process_id (inf);
    686   if (process_id.handle == AMD_DBGAPI_PROCESS_NONE.handle)
    687     return;
    688 
    689   solib_info *info = get_solib_info (inf);
    690 
    691   info->solib_list.clear ();
    692   std::vector<rocm_so> &sos = info->solib_list;
    693 
    694   amd_dbgapi_code_object_id_t *code_object_list;
    695   size_t count;
    696 
    697   amd_dbgapi_status_t status
    698     = amd_dbgapi_process_code_object_list (process_id, &count,
    699 					   &code_object_list, nullptr);
    700   if (status != AMD_DBGAPI_STATUS_SUCCESS)
    701     {
    702       warning (_("amd_dbgapi_process_code_object_list failed (%s)"),
    703 	       get_status_string (status));
    704       return;
    705     }
    706 
    707   for (size_t i = 0; i < count; ++i)
    708     {
    709       CORE_ADDR l_addr;
    710       char *uri_bytes;
    711 
    712       status = amd_dbgapi_code_object_get_info
    713 	(code_object_list[i], AMD_DBGAPI_CODE_OBJECT_INFO_LOAD_ADDRESS,
    714 	 sizeof (l_addr), &l_addr);
    715       if (status != AMD_DBGAPI_STATUS_SUCCESS)
    716 	continue;
    717 
    718       status = amd_dbgapi_code_object_get_info
    719 	(code_object_list[i], AMD_DBGAPI_CODE_OBJECT_INFO_URI_NAME,
    720 	 sizeof (uri_bytes), &uri_bytes);
    721       if (status != AMD_DBGAPI_STATUS_SUCCESS)
    722 	continue;
    723 
    724       gdb::unique_xmalloc_ptr<char> uri_bytes_holder (uri_bytes);
    725 
    726       lm_info_svr4_up li = std::make_unique<lm_info_svr4> ();
    727       li->l_addr = l_addr;
    728 
    729       /* Generate a unique name so that code objects with the same URI but
    730 	 different load addresses are seen by gdb core as different shared
    731 	 objects.  */
    732       std::string unique_name
    733 	= string_printf ("code_object_%ld", code_object_list[i].handle);
    734 
    735       sos.emplace_back (uri_bytes, std::move (unique_name), std::move (li));
    736     }
    737 
    738   xfree (code_object_list);
    739 
    740   if (rocm_solib_ops.current_sos == NULL)
    741     {
    742       /* Override what we need to.  */
    743       rocm_solib_ops = svr4_so_ops;
    744       rocm_solib_ops.current_sos = rocm_solib_current_sos;
    745       rocm_solib_ops.solib_create_inferior_hook
    746 	= rocm_solib_create_inferior_hook;
    747       rocm_solib_ops.bfd_open = rocm_solib_bfd_open;
    748       rocm_solib_ops.relocate_section_addresses
    749 	= rocm_solib_relocate_section_addresses;
    750       rocm_solib_ops.handle_event = rocm_solib_handle_event;
    751 
    752       /* Engage the ROCm so_ops.  */
    753       set_gdbarch_so_ops (current_inferior ()->arch (), &rocm_solib_ops);
    754     }
    755 }
    756 
    757 static void
    758 rocm_solib_target_inferior_created (inferior *inf)
    759 {
    760   get_solib_info (inf)->solib_list.clear ();
    761 
    762   rocm_update_solib_list ();
    763 
    764   /* Force GDB to reload the solibs.  */
    765   current_inferior ()->pspace->clear_solib_cache ();
    766   solib_add (nullptr, 0, auto_solib_add);
    767 }
    768 
    769 /* -Wmissing-prototypes */
    770 extern initialize_file_ftype _initialize_rocm_solib;
    771 
    772 void
    773 _initialize_rocm_solib ()
    774 {
    775   /* The dependency on the amd-dbgapi exists because solib-rocm's
    776      inferior_created observer needs amd-dbgapi to have attached the process,
    777      which happens in amd_dbgapi_target's inferior_created observer.  */
    778   gdb::observers::inferior_created.attach
    779     (rocm_solib_target_inferior_created,
    780      "solib-rocm",
    781      { &get_amd_dbgapi_target_inferior_created_observer_token () });
    782 }
    783