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