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