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