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