gdb: rename things related to step over chains
[deliverable/binutils-gdb.git] / gdb / solib-rocm.c
CommitLineData
abeeff98
LM
1/* Handle ROCm Code Objects for GDB, the GNU Debugger.
2
ca9af5a1
LM
3 Copyright (C) 2019-2020 Free Software Foundation, Inc.
4 Copyright (C) 2019-2020 Advanced Micro Devices, Inc. All rights reserved.
abeeff98
LM
5
6 This file is part of GDB.
7
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>. */
20
21#include "defs.h"
22
23#include "arch-utils.h"
24#include "elf-bfd.h"
84281c0e 25#include "gdb/fileio.h"
abeeff98
LM
26#include "gdbcore.h"
27#include "inferior.h"
28#include "objfiles.h"
29#include "observable.h"
30#include "rocm-tdep.h"
31#include "solib-svr4.h"
32#include "solib.h"
33#include "solist.h"
34#include "symfile.h"
35
36#include <functional>
37#include <string>
84281c0e 38#include <unordered_map>
abeeff98
LM
39
40/* ROCm-specific inferior data. */
41
42struct solib_info
43{
44 /* List of code objects loaded into the inferior. */
45 struct so_list *solib_list;
46};
47
48/* Per-inferior data key. */
49static const struct inferior_key<solib_info> rocm_solib_data;
50
51struct target_so_ops rocm_solib_ops;
52
53/* Free the solib linked list. */
54
55static void
56rocm_free_solib_list (struct solib_info *info)
57{
58 while (info->solib_list != NULL)
59 {
60 struct so_list *next = info->solib_list->next;
61
62 free_so (info->solib_list);
63 info->solib_list = next;
64 }
65
66 info->solib_list = NULL;
67}
68
69/* Fetch the solib_info data for the current inferior. */
70
71static struct solib_info *
72get_solib_info (void)
73{
74 struct inferior *inf = current_inferior ();
75
76 struct solib_info *info = rocm_solib_data.get (inf);
77 if (info == NULL)
78 info = rocm_solib_data.emplace (inf);
79
80 return info;
81}
82
83/* Relocate section addresses. */
84
85static void
86rocm_solib_relocate_section_addresses (struct so_list *so,
87 struct target_section *sec)
88{
89 if (!rocm_is_amdgcn_gdbarch (gdbarch_from_bfd (so->abfd)))
90 {
91 svr4_so_ops.relocate_section_addresses (so, sec);
92 return;
93 }
94
95 lm_info_svr4 *li = (lm_info_svr4 *)so->lm_info;
96 sec->addr = sec->addr + li->l_addr;
97 sec->endaddr = sec->endaddr + li->l_addr;
98}
99
100/* Make a deep copy of the solib linked list. */
101
102static struct so_list *
103rocm_solib_copy_list (const struct so_list *src)
104{
105 struct so_list *dst = NULL;
106 struct so_list **link = &dst;
107
108 while (src != NULL)
109 {
110 struct so_list *newobj;
111
112 newobj = XNEW (struct so_list);
113 memcpy (newobj, src, sizeof (struct so_list));
114
115 lm_info_svr4 *src_li = (lm_info_svr4 *)src->lm_info;
116 newobj->lm_info = new lm_info_svr4 (*src_li);
117
118 newobj->next = NULL;
119 *link = newobj;
120 link = &newobj->next;
121
122 src = src->next;
123 }
124
125 return dst;
126}
127
128/* Build a list of `struct so_list' objects describing the shared
129 objects currently loaded in the inferior. */
130
131static struct so_list *
132rocm_solib_current_sos (void)
133{
134 /* First, retrieve the host-side shared library list. */
135 struct so_list *head = svr4_so_ops.current_sos ();
136
137 /* Then, the device-side shared library list. */
138 struct so_list *list = get_solib_info ()->solib_list;
139
140 if (!list)
141 return head;
142
143 list = rocm_solib_copy_list (list);
144
145 if (!head)
146 return list;
147
148 /* Append our libraries to the end of the list. */
149 struct so_list *tail;
150 for (tail = head; tail->next; tail = tail->next)
151 /* Nothing. */;
152 tail->next = list;
153
154 return head;
155}
156
84281c0e 157struct rocm_code_object_stream
abeeff98 158{
84281c0e
LM
159 /* The target file descriptor for this stream */
160 int fd;
161
162 /* The offset of the ELF file image in the target file. */
163 ULONGEST offset;
abeeff98
LM
164
165 /* The size of the ELF file image. */
166 ULONGEST size;
167};
168
169static void *
84281c0e 170rocm_bfd_iovec_open (bfd *abfd, void *inferior)
abeeff98 171{
84281c0e
LM
172 std::string uri (bfd_get_filename (abfd));
173
174 std::string protocol_delim ("://");
175 size_t protocol_end = uri.find (protocol_delim);
176 std::string protocol = uri.substr (0, protocol_end);
177 protocol_end += protocol_delim.length ();
178
179 std::transform (protocol.begin (), protocol.end (), protocol.begin (),
180 [] (unsigned char c) { return std::tolower (c); });
181 if (protocol != "file")
182 {
183 warning (_ ("`%s': protocol not supported: %s"), uri.c_str (),
184 protocol.c_str ());
185 bfd_set_error (bfd_error_bad_value);
186 return nullptr;
187 }
188
189 std::string path;
190 size_t path_end = uri.find_first_of ("#?", protocol_end);
191 if (path_end != std::string::npos)
192 path = uri.substr (protocol_end, path_end++ - protocol_end);
193 else
194 path = uri.substr (protocol_end);
195
196 /* %-decode the string. */
197 std::string decoded_path;
198 decoded_path.reserve (path.length ());
199 for (size_t i = 0; i < path.length (); ++i)
200 if (path[i] == '%' && std::isxdigit (path[i + 1])
201 && std::isxdigit (path[i + 2]))
202 {
203 decoded_path += std::stoi (path.substr (i + 1, 2), 0, 16);
204 i += 2;
205 }
206 else
207 decoded_path += path[i];
208
209 /* Tokenize the query/fragment. */
210 std::vector<std::string> tokens;
211 size_t pos, last = path_end;
212 while ((pos = uri.find ('&', last)) != std::string::npos)
213 {
214 tokens.emplace_back (uri.substr (last, pos - last));
215 last = pos + 1;
216 }
217 if (last != std::string::npos)
218 tokens.emplace_back (uri.substr (last));
219
220 /* Create a tag-value map from the tokenized query/fragment. */
221 std::unordered_map<std::string, std::string> params;
222 std::for_each (tokens.begin (), tokens.end (), [&] (std::string &token) {
223 size_t delim = token.find ('=');
224 if (delim != std::string::npos)
225 params.emplace (token.substr (0, delim), token.substr (delim + 1));
226 });
227
228 gdb::unique_xmalloc_ptr<rocm_code_object_stream> stream (
229 XCNEW (rocm_code_object_stream));
230 try
231 {
232 auto offset_it = params.find ("offset");
233 if (offset_it != params.end ())
234 stream->offset = std::stoul (offset_it->second, nullptr, 0);
235
236 auto size_it = params.find ("size");
237 if (size_it != params.end ())
238 if (!(stream->size = std::stoul (size_it->second, nullptr, 0)))
239 {
240 bfd_set_error (bfd_error_bad_value);
241 return nullptr;
242 }
243 }
244 catch (...)
245 {
246 bfd_set_error (bfd_error_bad_value);
247 return nullptr;
248 }
249
250 int fd, target_errno;
251 fd = target_fileio_open (static_cast<struct inferior *> (inferior),
252 decoded_path.c_str (), FILEIO_O_RDONLY, 0,
253 &target_errno);
254 if (fd == -1)
255 {
256 /* FIXME: Should we set errno? Move fileio_errno_to_host from gdb_bfd.c
257 to fileio.cc */
258 /* errno = fileio_errno_to_host (target_errno); */
259 bfd_set_error (bfd_error_system_call);
260 return nullptr;
261 }
262
263 stream->fd = fd;
264 return stream.release ();
abeeff98
LM
265}
266
267static int
84281c0e 268rocm_bfd_iovec_close (bfd *nbfd, void *data)
abeeff98 269{
84281c0e
LM
270 auto *stream = static_cast<rocm_code_object_stream *> (data);
271
272 int target_errno;
273 target_fileio_close (stream->fd, &target_errno);
274
abeeff98
LM
275 xfree (stream);
276 return 0;
277}
278
279static file_ptr
84281c0e 280rocm_bfd_iovec_pread (bfd *abfd, void *data, void *buf, file_ptr size,
abeeff98
LM
281 file_ptr offset)
282{
84281c0e
LM
283 auto *stream = static_cast<rocm_code_object_stream *> (data);
284 int target_errno;
abeeff98 285
84281c0e
LM
286 file_ptr nbytes = 0;
287 while (size > 0)
abeeff98 288 {
84281c0e
LM
289 QUIT;
290
291 file_ptr bytes_read = target_fileio_pread (
292 stream->fd, static_cast<gdb_byte *> (buf) + nbytes, size,
293 stream->offset + offset + nbytes, &target_errno);
294
295 if (bytes_read == 0)
296 break;
297
298 if (bytes_read < 0)
299 {
300 /* FIXME: Should we set errno? */
301 /* errno = fileio_errno_to_host (target_errno); */
302 bfd_set_error (bfd_error_system_call);
303 return -1;
304 }
305
306 nbytes += bytes_read;
307 size -= bytes_read;
abeeff98
LM
308 }
309
310 return nbytes;
311}
312
313static int
84281c0e 314rocm_bfd_iovec_stat (bfd *abfd, void *data, struct stat *sb)
abeeff98 315{
84281c0e
LM
316 auto *stream = static_cast<rocm_code_object_stream *> (data);
317 int target_errno;
318
319 /* If stream->size is 0, the URI size parameter was not set. */
320 if (!stream->size)
321 {
322 struct stat stat;
323 if (target_fileio_fstat (stream->fd, &stat, &target_errno) < 0)
324 {
325 /* FIXME: Should we set errno? */
326 /* errno = fileio_errno_to_host (target_errno); */
327 bfd_set_error (bfd_error_system_call);
328 return -1;
329 }
330
331 /* Check that the offset is valid. */
332 if (stream->offset >= stat.st_size)
333 {
334 bfd_set_error (bfd_error_bad_value);
335 return -1;
336 }
337
338 stream->size = stat.st_size - stream->offset;
339 }
340
abeeff98 341 memset (sb, '\0', sizeof (struct stat));
84281c0e 342 sb->st_size = stream->size;
abeeff98
LM
343 return 0;
344}
345
346static gdb_bfd_ref_ptr
347rocm_solib_bfd_open (const char *pathname)
348{
84281c0e
LM
349 /* Handle regular files with SVR4 open. */
350 if (!strstr (pathname, "://"))
abeeff98
LM
351 return svr4_so_ops.bfd_open (pathname);
352
abeeff98 353 gdb_bfd_ref_ptr abfd (gdb_bfd_openr_iovec (
84281c0e 354 pathname, "elf64-amdgcn", rocm_bfd_iovec_open, current_inferior (),
abeeff98
LM
355 rocm_bfd_iovec_pread, rocm_bfd_iovec_close, rocm_bfd_iovec_stat));
356
84281c0e
LM
357 if (abfd == nullptr)
358 error (_ ("Could not open `%s' as an executable file: %s"), pathname,
359 bfd_errmsg (bfd_get_error ()));
360
abeeff98
LM
361 /* Check bfd format. */
362 if (!bfd_check_format (abfd.get (), bfd_object))
363 error (_ ("`%s': not in executable format: %s"),
364 bfd_get_filename (abfd.get ()), bfd_errmsg (bfd_get_error ()));
365
366 unsigned char osabi = elf_elfheader (abfd)->e_ident[EI_OSABI];
367 unsigned char osabiversion = elf_elfheader (abfd)->e_ident[EI_ABIVERSION];
368
369 /* Make a check if the code object in the elf is V3. ROCM-gdb has
370 support only for V3. */
371 if (osabi != ELFOSABI_AMDGPU_HSA)
372 error (_ ("`%s': ELF file OS ABI invalid (%d)."),
373 bfd_get_filename (abfd.get ()), osabi);
374
375 if (osabi == ELFOSABI_AMDGPU_HSA && osabiversion < 1)
376 error (_ ("`%s': ELF file ABI version (%d) is not supported."),
377 bfd_get_filename (abfd.get ()), osabiversion);
378
379 return abfd;
380}
381
382static void
383rocm_solib_create_inferior_hook (int from_tty)
384{
385 rocm_free_solib_list (get_solib_info ());
386
387 svr4_so_ops.solib_create_inferior_hook (from_tty);
388}
389
390static void
391rocm_update_solib_list ()
392{
393 amd_dbgapi_process_id_t process_id = get_amd_dbgapi_process_id ();
84281c0e
LM
394 if (process_id.handle == AMD_DBGAPI_PROCESS_NONE.handle)
395 return;
396
abeeff98
LM
397 solib_info *info = get_solib_info ();
398 amd_dbgapi_status_t status;
399
400 rocm_free_solib_list (info);
401 struct so_list **link = &info->solib_list;
402
403 amd_dbgapi_code_object_id_t *code_object_list;
404 size_t count;
405
406 if ((status = amd_dbgapi_code_object_list (process_id, &count,
407 &code_object_list, nullptr))
408 != AMD_DBGAPI_STATUS_SUCCESS)
409 {
410 warning (_ ("amd_dbgapi_code_object_list failed (%d)"), status);
411 return;
412 }
413
414 for (size_t i = 0; i < count; ++i)
415 {
416 struct so_list *so = XCNEW (struct so_list);
417 lm_info_svr4 *li = new lm_info_svr4;
418 so->lm_info = li;
419
420 char *uri_bytes;
421
422 if (amd_dbgapi_code_object_get_info (
423 process_id, code_object_list[i],
424 AMD_DBGAPI_CODE_OBJECT_INFO_LOAD_ADDRESS, sizeof (li->l_addr),
425 &li->l_addr)
426 != AMD_DBGAPI_STATUS_SUCCESS
427 || amd_dbgapi_code_object_get_info (
428 process_id, code_object_list[i],
429 AMD_DBGAPI_CODE_OBJECT_INFO_URI_NAME, sizeof (uri_bytes),
430 &uri_bytes)
431 != AMD_DBGAPI_STATUS_SUCCESS)
432 continue;
433
84281c0e
LM
434 strncpy (so->so_name, uri_bytes, sizeof (so->so_name));
435 so->so_name[sizeof (so->so_name) - 1] = '\0';
abeeff98
LM
436 xfree (uri_bytes);
437
abeeff98
LM
438 strcpy (so->so_original_name, so->so_name);
439
440 so->next = nullptr;
441 *link = so;
442 link = &so->next;
443 }
444
445 xfree (code_object_list);
446
447 /* Force GDB to reload the solibs. */
448 clear_program_space_solib_cache (current_inferior ()->pspace);
449
450 /* Switch terminal for any messages produced by
451 breakpoint_re_set. */
452 target_terminal::ours_for_output ();
453
454 solib_add (NULL, 0, auto_solib_add);
455
456 /* Switch it back. */
457 target_terminal::inferior ();
458}
459
460static void
461rocm_solib_dbgapi_activated ()
462{
463 if (rocm_solib_ops.current_sos == NULL)
464 {
465 /* Override what we need to */
466 rocm_solib_ops = svr4_so_ops;
467 rocm_solib_ops.current_sos = rocm_solib_current_sos;
468 rocm_solib_ops.solib_create_inferior_hook
469 = rocm_solib_create_inferior_hook;
470 rocm_solib_ops.bfd_open = rocm_solib_bfd_open;
471 rocm_solib_ops.relocate_section_addresses
472 = rocm_solib_relocate_section_addresses;
473 }
474
475 /* Engage the ROCm so_ops. */
476 set_solib_ops (target_gdbarch (), &rocm_solib_ops);
477}
478
479static void
480rocm_solib_dbgapi_deactivated ()
481{
482 /* Disengage the ROCm so_ops. */
483 set_solib_ops (target_gdbarch (), &svr4_so_ops);
0fdeaa80 484 rocm_update_solib_list ();
abeeff98
LM
485}
486
487static void
488rocm_solib_target_inferior_created (struct target_ops *target, int from_tty)
489{
490 rocm_free_solib_list (get_solib_info ());
491 rocm_update_solib_list ();
492}
493
494/* -Wmissing-prototypes */
495extern initialize_file_ftype _initialize_rocm_solib;
496
497void
498_initialize_rocm_solib (void)
499{
500 /* Install our observers. */
501 amd_dbgapi_activated.attach (rocm_solib_dbgapi_activated);
502 amd_dbgapi_deactivated.attach (rocm_solib_dbgapi_deactivated);
503 amd_dbgapi_code_object_list_updated.attach (rocm_update_solib_list);
504
505 /* FIXME: remove this when we can clear the solist in
506 rocm_solib_create_inferior_hook. */
507 gdb::observers::inferior_created.attach (rocm_solib_target_inferior_created);
508}
This page took 0.044799 seconds and 4 git commands to generate.