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