]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - gdb/solib-rocm.c
Update copyright year range in header of all files managed by GDB
[thirdparty/binutils-gdb.git] / gdb / solib-rocm.c
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 #include "defs.h"
21
22 #include "amd-dbgapi-target.h"
23 #include "amdgpu-tdep.h"
24 #include "arch-utils.h"
25 #include "elf-bfd.h"
26 #include "elf/amdgpu.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 target_so_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 (shobj &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<shobj>
208 so_list_from_rocm_sos (const std::vector<rocm_so> &sos)
209 {
210 intrusive_list<shobj> dst;
211
212 for (const rocm_so &so : sos)
213 {
214 struct shobj *newobj = new struct shobj;
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 shobj' objects describing the shared
227 objects currently loaded in the inferior. */
228
229 static intrusive_list<shobj>
230 rocm_solib_current_sos ()
231 {
232 /* First, retrieve the host-side shared library list. */
233 intrusive_list<shobj> 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<shobj> 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 (path[i + 1])
462 && std::isxdigit (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 }