Unregister the the rocm event handler
[deliverable/binutils-gdb.git] / gdb / rocm-tdep.c
CommitLineData
abeeff98
LM
1/* Target-dependent code for ROCm.
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 "amdgcn-rocm-tdep.h"
24#include "arch-utils.h"
25#include "cli/cli-style.h"
26#include "environ.h"
27#include "event-loop.h"
28#include "filenames.h"
29#include "gdbcmd.h"
30#include "gdbcore.h"
31#include "gdbsupport/filestuff.h"
32#include "gdbsupport/scoped_fd.h"
33#include "gdbthread.h"
34#include "hashtab.h"
35#include "inf-loop.h"
36#include "inferior.h"
37#include "location.h"
38#include "objfiles.h"
39#include "observable.h"
40#include "progspace-and-thread.h"
41#include "regcache.h"
42#include "rocm-tdep.h"
43#include "solib.h"
44#include "solist.h"
45#include "symfile.h"
46
47#include <dlfcn.h>
48#include <list>
49#include <set>
50#include <signal.h>
51#include <stdarg.h>
52#include <unordered_map>
53
54#include <amd-dbgapi.h>
55
56/* Big enough to hold the size of the largest register in bytes. */
57#define AMDGCN_MAX_REGISTER_SIZE 256
58
59#define DEFINE_OBSERVABLE(name) decltype (name) name (#name)
60
61DEFINE_OBSERVABLE (amd_dbgapi_activated);
62DEFINE_OBSERVABLE (amd_dbgapi_deactivated);
63DEFINE_OBSERVABLE (amd_dbgapi_code_object_list_updated);
64
65#undef DEFINE_OBSERVABLE
66
67struct rocm_notify_shared_library_info
68{
69 std::string compare; /* Compare loaded library names with this string. */
70 struct so_list *solib;
71 bool is_loaded;
72};
73
74/* ROCm-specific inferior data. */
75
76struct rocm_inferior_info
77{
78 /* The amd_dbgapi_process_id for this inferior. */
b8ff49b7 79 amd_dbgapi_process_id_t process_id{ AMD_DBGAPI_PROCESS_NONE };
abeeff98
LM
80
81 /* The amd_dbgapi_notifier_t for this inferior. */
b8ff49b7 82 amd_dbgapi_notifier_t notifier{ -1 };
abeeff98
LM
83
84 /* True if commit_resume should all-start the GPU queues. */
85 bool commit_resume_all_start;
86
243f18ba
LM
87 /* True is the inferior has exited. */
88 bool has_exited{ false };
89
abeeff98
LM
90 std::unordered_map<decltype (amd_dbgapi_breakpoint_id_t::handle),
91 struct breakpoint *>
92 breakpoint_map;
93
94 /* List of pending events the rocm target retrieved from the dbgapi. */
95 std::list<std::pair<amd_dbgapi_wave_id_t, amd_dbgapi_wave_stop_reason_t>>
96 wave_stop_events;
97
98 /* Map of rocm_notify_shared_library_info's for libraries that have been
99 registered to receive notifications when loading/unloading. */
100 std::unordered_map<decltype (amd_dbgapi_shared_library_id_t::handle),
101 struct rocm_notify_shared_library_info>
102 notify_solib_map;
103};
104
105static amd_dbgapi_event_id_t
106rocm_process_event_queue (amd_dbgapi_event_kind_t until_event_kind
107 = AMD_DBGAPI_EVENT_KIND_NONE);
108
109/* Return the inferior's rocm_inferior_info struct. */
110static struct rocm_inferior_info *
111get_rocm_inferior_info (struct inferior *inferior = nullptr);
112
113static const target_info rocm_ops_info
114 = { "rocm", N_ ("ROCm GPU debugging support"),
115 N_ ("ROCm GPU debugging support") };
116
117static amd_dbgapi_log_level_t get_debug_amd_dbgapi_log_level ();
118
119struct rocm_target_ops final : public target_ops
120{
121 const target_info &
122 info () const override
123 {
124 return rocm_ops_info;
125 }
126 strata
127 stratum () const override
128 {
129 return arch_stratum;
130 }
131
36f3baab 132 void close () override;
abeeff98
LM
133 void mourn_inferior () override;
134
135 void async (int enable) override;
136
137 ptid_t wait (ptid_t, struct target_waitstatus *, int) override;
138 void resume (ptid_t, int, enum gdb_signal) override;
139 void commit_resume () override;
140 void stop (ptid_t ptid) override;
141
142 void fetch_registers (struct regcache *, int) override;
143 void store_registers (struct regcache *, int) override;
144
145 void update_thread_list () override;
146
147 struct gdbarch *thread_architecture (ptid_t) override;
148
149 std::string pid_to_str (ptid_t ptid) override;
150
151 const char *thread_name (thread_info *tp) override;
152
153 const char *extra_thread_info (thread_info *tp) override;
154
155 bool thread_alive (ptid_t ptid) override;
156
157 enum target_xfer_status xfer_partial (enum target_object object,
158 const char *annex, gdb_byte *readbuf,
159 const gdb_byte *writebuf,
160 ULONGEST offset, ULONGEST len,
161 ULONGEST *xfered_len) override;
162
163 bool
164 stopped_by_watchpoint () override
165 {
166 return !ptid_is_gpu (inferior_ptid)
167 && beneath ()->stopped_by_watchpoint ();
168 }
169
170 bool
171 stopped_data_address (CORE_ADDR *addr_p) override
172 {
173 return !ptid_is_gpu (inferior_ptid)
174 && beneath ()->stopped_data_address (addr_p);
175 }
176
177 bool
178 supports_stopped_by_sw_breakpoint () override
179 {
180 return true;
181 }
182
183 bool stopped_by_sw_breakpoint () override;
184
185 bool
186 stopped_by_hw_breakpoint () override
187 {
188 return !ptid_is_gpu (inferior_ptid)
189 && beneath ()->stopped_by_hw_breakpoint ();
190 }
191};
192
193/* ROCm's target vector. */
194static struct rocm_target_ops rocm_ops;
195
196/* ROCm breakpoint ops. */
197static struct breakpoint_ops rocm_breakpoint_ops;
198
199/* Per-inferior data key. */
200static const struct inferior_key<rocm_inferior_info> rocm_inferior_data;
201
202/* The read/write ends of the pipe registered as waitable file in the
203 event loop. */
204static int rocm_event_pipe[2] = { -1, -1 };
205
206/* Flush the event pipe. */
207
5cf3a303 208static void
abeeff98
LM
209async_file_flush (void)
210{
211 int ret;
212 char buf;
213
214 do
215 {
216 ret = read (rocm_event_pipe[0], &buf, 1);
217 }
218 while (ret >= 0 || (ret == -1 && errno == EINTR));
219}
220
221/* Put something (anything, doesn't matter what, or how much) in event
222 pipe, so that the select/poll in the event-loop realizes we have
223 something to process. */
224
225static void
226async_file_mark (void)
227{
228 int ret;
229
230 /* It doesn't really matter what the pipe contains, as long we end
231 up with something in it. Might as well flush the previous
232 left-overs. */
233 async_file_flush ();
234
235 do
236 {
237 ret = write (rocm_event_pipe[1], "+", 1);
238 }
239 while (ret == -1 && errno == EINTR);
240
241 /* Ignore EAGAIN. If the pipe is full, the event loop will already
242 be awakened anyway. */
243}
244
245/* Fetch the rocm_inferior_info data for the given inferior. */
246
247static struct rocm_inferior_info *
248get_rocm_inferior_info (struct inferior *inferior)
249{
250 if (!inferior)
251 inferior = current_inferior ();
252
253 struct rocm_inferior_info *info = rocm_inferior_data.get (inferior);
254
255 if (!info)
256 info = rocm_inferior_data.emplace (inferior);
257
258 return info;
259}
260
261/* Fetch the amd_dbgapi_process_id for the given inferior. */
262
263amd_dbgapi_process_id_t
264get_amd_dbgapi_process_id (struct inferior *inferior)
265{
266 return get_rocm_inferior_info (inferior)->process_id;
267}
268
9e275233
LM
269static void
270rocm_breakpoint_re_set (struct breakpoint *b)
271{
272}
273
abeeff98
LM
274static void
275rocm_breakpoint_check_status (struct bpstats *bs)
276{
277 struct rocm_inferior_info *info = get_rocm_inferior_info ();
278 amd_dbgapi_process_id_t process_id = info->process_id;
279 amd_dbgapi_status_t status;
280
281 bs->stop = 0;
282 bs->print_it = print_it_noop;
283
284 /* Find the address the breakpoint is set at. */
285 auto it = std::find_if (
286 info->breakpoint_map.begin (), info->breakpoint_map.end (),
287 [=] (const decltype (info->breakpoint_map)::value_type &value) {
288 return value.second == bs->breakpoint_at;
289 });
290
291 if (it == info->breakpoint_map.end ())
292 error (_ ("Could not find breakpoint_id for breakpoint at %#lx"),
293 bs->bp_location_at->address);
294
295 amd_dbgapi_breakpoint_id_t breakpoint_id{ it->first };
296 amd_dbgapi_breakpoint_action_t action;
297
298 status = amd_dbgapi_report_breakpoint_hit (process_id, breakpoint_id,
299 inferior_thread (), &action);
300
301 if (status != AMD_DBGAPI_STATUS_SUCCESS)
302 error (_ ("amd_dbgapi_report_breakpoint_hit failed: breakpoint_%ld "
303 "at %#lx (rc=%d)"),
304 breakpoint_id.handle, bs->bp_location_at->address, status);
305
306 if (action == AMD_DBGAPI_BREAKPOINT_ACTION_RESUME)
307 return;
308
309 /* If the action is AMD_DBGAPI_BREAKPOINT_ACTION_HALT, we need to wait until
310 a breakpoint resume event for this breakpoint_id is seen. */
311
312 amd_dbgapi_event_id_t resume_event_id
313 = rocm_process_event_queue (AMD_DBGAPI_EVENT_KIND_BREAKPOINT_RESUME);
314
315 /* We should always get a breakpoint_resume event after processing all
316 events generated by reporting the breakpoint was hit. */
317 gdb_assert (resume_event_id.handle != AMD_DBGAPI_EVENT_NONE.handle);
318
319 amd_dbgapi_breakpoint_id_t resume_breakpoint_id;
320 status = amd_dbgapi_event_get_info (
321 process_id, resume_event_id, AMD_DBGAPI_EVENT_INFO_BREAKPOINT,
322 sizeof (resume_breakpoint_id), &resume_breakpoint_id);
323
324 if (status != AMD_DBGAPI_STATUS_SUCCESS)
325 error (_ ("amd_dbgapi_event_get_info failed (rc=%d)"), status);
326
327 /* The debugger API guarantees that [breakpoint_hit...resume_breakpoint]
328 sequences cannot interleave, so this breakpoint resume event must be
329 for our breakpoint_id. */
330 if (resume_breakpoint_id.handle != breakpoint_id.handle)
331 error (_ ("breakpoint resume event is not for this breakpoint. "
332 "Expected breakpoint_%ld, got breakpoint_%ld"),
333 breakpoint_id.handle, resume_breakpoint_id.handle);
334
335 amd_dbgapi_event_processed (process_id, resume_event_id);
336}
337
338static void
339rocm_target_dbgapi_activated ()
340{
341 /* FIXME: only push on the first activation. */
342 /* Engage the ROCm target_ops and so_ops. */
343 push_target (&rocm_ops);
344}
345
346static void
347rocm_target_dbgapi_deactivated ()
348{
349 /* FIXME: only unpush on the last activation. */
350 /* Disengage the ROCm target_ops. */
351 unpush_target (&rocm_ops);
352}
353
354bool
355rocm_target_ops::thread_alive (ptid_t ptid)
356{
357 if (!ptid_is_gpu (ptid))
358 return beneath ()->thread_alive (ptid);
359
360 /* Check that the wave_id is valid. */
361
362 inferior *inf = find_inferior_ptid (ptid);
363 if (!inf)
364 return false;
365
366 amd_dbgapi_wave_state_t state;
367 return amd_dbgapi_wave_get_info (
368 get_amd_dbgapi_process_id (inf), get_amd_dbgapi_wave_id (ptid),
369 AMD_DBGAPI_WAVE_INFO_STATE, sizeof (state), &state)
370 == AMD_DBGAPI_STATUS_SUCCESS;
371}
372
373const char *
374rocm_target_ops::thread_name (thread_info *tp)
375{
376 if (!ptid_is_gpu (tp->ptid))
377 return beneath ()->thread_name (tp);
378
223465e7
LM
379 /* Return the process's comm value—that is, the command name associated with
380 the process. */
abeeff98 381
223465e7
LM
382 char comm_path[128];
383 xsnprintf (comm_path, sizeof (comm_path), "/proc/%ld/comm",
384 (long)tp->ptid.pid ());
385
386 gdb_file_up comm_file = gdb_fopen_cloexec (comm_path, "r");
387 if (!comm_file)
388 return nullptr;
abeeff98 389
223465e7
LM
390#if !defined(TASK_COMM_LEN)
391#define TASK_COMM_LEN 16 /* As defined in the kernel's sched.h. */
392#endif
abeeff98 393
223465e7
LM
394 static char comm_buf[TASK_COMM_LEN];
395 const char *comm_value;
abeeff98 396
223465e7
LM
397 comm_value = fgets (comm_buf, sizeof (comm_buf), comm_file.get ());
398 comm_buf[sizeof (comm_buf) - 1] = '\0';
399
400 /* Make sure there is no newline at the end. */
401 if (comm_value)
402 {
403 for (int i = 0; i < sizeof (comm_buf); i++)
404 if (comm_buf[i] == '\n')
405 {
406 comm_buf[i] = '\0';
407 break;
408 }
abeeff98
LM
409 }
410
223465e7 411 return comm_value;
abeeff98
LM
412}
413
414std::string
415rocm_target_ops::pid_to_str (ptid_t ptid)
416{
417 if (!ptid_is_gpu (ptid))
418 {
419 return beneath ()->pid_to_str (ptid);
420 }
421
422 amd_dbgapi_process_id_t process_id = get_amd_dbgapi_process_id ();
423 amd_dbgapi_wave_id_t wave_id = get_amd_dbgapi_wave_id (ptid);
424 amd_dbgapi_dispatch_id_t dispatch_id;
425 uint32_t group_ids[3], wave_in_group;
426
427 if (amd_dbgapi_wave_get_info (process_id, wave_id,
428 AMD_DBGAPI_WAVE_INFO_DISPATCH,
429 sizeof (dispatch_id), &dispatch_id)
430 != AMD_DBGAPI_STATUS_SUCCESS
431 || amd_dbgapi_wave_get_info (process_id, wave_id,
432 AMD_DBGAPI_WAVE_INFO_WORK_GROUP_COORD,
433 sizeof (group_ids), &group_ids)
434 != AMD_DBGAPI_STATUS_SUCCESS
435 || amd_dbgapi_wave_get_info (
436 process_id, wave_id,
437 AMD_DBGAPI_WAVE_INFO_WAVE_NUMBER_IN_WORK_GROUP,
438 sizeof (wave_in_group), &wave_in_group)
439 != AMD_DBGAPI_STATUS_SUCCESS)
8f156997 440 return std::string ("AMDGPU Thread");
abeeff98 441 else
8f156997 442 return string_printf ("AMDGPU Thread %ld.%ld (%d,%d,%d)/%d",
abeeff98
LM
443 dispatch_id.handle, wave_id.handle, group_ids[2],
444 group_ids[1], group_ids[0], wave_in_group);
445}
446
447const char *
448rocm_target_ops::extra_thread_info (thread_info *tp)
449{
450 if (!ptid_is_gpu (tp->ptid))
451 beneath ()->extra_thread_info (tp);
452
453 return NULL;
454}
455
456enum target_xfer_status
457rocm_target_ops::xfer_partial (enum target_object object, const char *annex,
458 gdb_byte *readbuf, const gdb_byte *writebuf,
459 ULONGEST offset, ULONGEST requested_len,
460 ULONGEST *xfered_len)
461{
462 gdb::optional<scoped_restore_current_thread> maybe_restore_thread;
463
464 if (ptid_is_gpu (inferior_ptid))
465 {
466 gdb_assert (requested_len && xfered_len && "checking invariants");
467
468 if (object != TARGET_OBJECT_MEMORY)
469 return TARGET_XFER_E_IO;
470
471 amd_dbgapi_process_id_t process_id = get_amd_dbgapi_process_id ();
472 amd_dbgapi_wave_id_t wave_id = get_amd_dbgapi_wave_id (inferior_ptid);
473
474 amd_dbgapi_architecture_id_t architecture_id;
475 amd_dbgapi_address_space_id_t address_space_id;
476
477 if (amd_dbgapi_wave_get_info (process_id, wave_id,
478 AMD_DBGAPI_WAVE_INFO_ARCHITECTURE,
479 sizeof (architecture_id), &architecture_id)
480 != AMD_DBGAPI_STATUS_SUCCESS
481 || amd_dbgapi_architecture_get_info (
482 architecture_id,
483 AMD_DBGAPI_ARCHITECTURE_INFO_DEFAULT_GLOBAL_ADDRESS_SPACE,
484 sizeof (address_space_id), &address_space_id)
485 != AMD_DBGAPI_STATUS_SUCCESS)
edc83450 486 return TARGET_XFER_EOF;
abeeff98
LM
487
488 size_t len = requested_len;
489 amd_dbgapi_status_t status;
490
491 if (readbuf)
492 status = amd_dbgapi_read_memory (
493 process_id, wave_id, 0, address_space_id, offset, &len, readbuf);
494 else
495 status = amd_dbgapi_write_memory (
496 process_id, wave_id, 0, address_space_id, offset, &len, writebuf);
497
498 if (status != AMD_DBGAPI_STATUS_SUCCESS)
edc83450 499 return TARGET_XFER_EOF;
abeeff98
LM
500
501 *xfered_len = len;
502 return TARGET_XFER_OK;
503 }
504 else
505 return beneath ()->xfer_partial (object, annex, readbuf, writebuf, offset,
506 requested_len, xfered_len);
507}
508
509void
510rocm_target_ops::resume (ptid_t ptid, int step, enum gdb_signal signo)
511{
512 struct rocm_inferior_info *info = get_rocm_inferior_info ();
513
514 if (debug_infrun)
515 fprintf_unfiltered (
516 gdb_stdlog,
517 "\e[1;34minfrun: rocm_target_ops::resume ([%d,%ld,%ld])\e[0m\n",
518 ptid.pid (), ptid.lwp (), ptid.tid ());
519
520 /* Check if the thread focus is on the GPU device. */
521 if (ptid == minus_one_ptid || !ptid_is_gpu (ptid))
522 {
523 beneath ()->resume (ptid, step, signo);
524 if (ptid != minus_one_ptid)
525 return;
526 }
527
528 /* A specific PTID means `step only this process id'. */
529 bool resume_one = ptid != minus_one_ptid && !ptid.is_pid ();
530 gdb_assert (resume_one || !step);
531
532 if (!resume_one)
533 error (_ ("internal error - unimplemented "));
534
535 amd_dbgapi_process_set_progress (info->process_id,
536 AMD_DBGAPI_PROGRESS_NO_FORWARD);
537
538 amd_dbgapi_status_t status = amd_dbgapi_wave_resume (
539 info->process_id, get_amd_dbgapi_wave_id (ptid),
540 step ? AMD_DBGAPI_RESUME_MODE_SINGLE_STEP
541 : AMD_DBGAPI_RESUME_MODE_NORMAL);
542 if (status != AMD_DBGAPI_STATUS_SUCCESS)
543 warning (_ ("Could not resume %s (rc=%d)"),
544 target_pid_to_str (ptid).c_str (), status);
545
546 info->commit_resume_all_start = true;
547}
548
549void
550rocm_target_ops::commit_resume ()
551{
552 struct rocm_inferior_info *info = get_rocm_inferior_info ();
553
554 if (debug_infrun)
555 fprintf_unfiltered (
556 gdb_stdlog,
557 "\e[1;34minfrun: rocm_target_ops::commit_resume ()\e[0m\n");
558
559 beneath ()->commit_resume ();
560
561 if (info->commit_resume_all_start)
562 {
563 amd_dbgapi_process_set_progress (info->process_id,
564 AMD_DBGAPI_PROGRESS_NORMAL);
565 info->commit_resume_all_start = false;
566 }
567
568 if (target_can_async_p ())
569 target_async (1);
570}
571
572static void
573rocm_target_stop_one_wave (ptid_t ptid)
574{
575 amd_dbgapi_status_t status;
576
577 status = amd_dbgapi_wave_stop (get_amd_dbgapi_process_id (),
578 get_amd_dbgapi_wave_id (ptid));
579
580 if (status == AMD_DBGAPI_STATUS_ERROR_INVALID_WAVE_ID)
581 {
582 /* the wave must have exited, set the thread status to reflect that. */
583 auto *tp = find_thread_ptid (ptid);
584 gdb_assert (tp);
585
586 tp->state = THREAD_EXITED;
587 }
588 else if (status != AMD_DBGAPI_STATUS_SUCCESS)
589 warning (_ ("Could not stop %s (rc=%d)"),
590 target_pid_to_str (ptid).c_str (), status);
591}
592
593void
594rocm_target_ops::stop (ptid_t ptid)
595{
596 if (debug_infrun)
597 fprintf_unfiltered (
598 gdb_stdlog,
599 "\e[1;34minfrun: rocm_target_ops::stop ([%d,%ld,%ld])\e[0m\n",
600 ptid.pid (), ptid.lwp (), ptid.tid ());
601
602 if (ptid == minus_one_ptid || !ptid_is_gpu (ptid))
603 {
604 beneath ()->stop (ptid);
605 if (ptid != minus_one_ptid)
606 return;
607 }
608
609 if (ptid == minus_one_ptid)
610 error (_ ("internal error - unimplemented "));
611
612 rocm_target_stop_one_wave (ptid);
613}
614
615static void
616handle_target_event (int error, gdb_client_data client_data)
617{
618 struct rocm_inferior_info *info = get_rocm_inferior_info ();
619 amd_dbgapi_process_id_t process_id = info->process_id;
620
621 amd_dbgapi_process_set_progress (process_id, AMD_DBGAPI_PROGRESS_NO_FORWARD);
622
623 /* Flush the async file first. */
624 if (target_is_async_p ())
625 async_file_flush ();
626
627 rocm_process_event_queue ();
628
629 /* In all-stop mode, unless the event queue is empty (spurious wake-up),
630 we can keep the process in progress_no_forward mode. The infrun loop
631 will enable forward progress when a thread is resumed. */
632 if (non_stop || info->wave_stop_events.empty ())
633 amd_dbgapi_process_set_progress (process_id, AMD_DBGAPI_PROGRESS_NORMAL);
634
635 if (!info->wave_stop_events.empty ())
636 inferior_event_handler (INF_REG_EVENT, nullptr);
637}
638
639void
640rocm_target_ops::async (int enable)
641{
642 beneath ()->async (enable);
643
644 if (enable)
645 {
646 if (rocm_event_pipe[0] != -1)
647 return;
648
649 if (gdb_pipe_cloexec (rocm_event_pipe) == -1)
650 internal_error (__FILE__, __LINE__, "creating event pipe failed.");
651
652 ::fcntl (rocm_event_pipe[0], F_SETFL, O_NONBLOCK);
653 ::fcntl (rocm_event_pipe[1], F_SETFL, O_NONBLOCK);
654
655 add_file_handler (rocm_event_pipe[0], handle_target_event, nullptr);
656
657 /* There may be pending events to handle. Tell the event loop
658 to poll them. */
659 async_file_mark ();
660 }
661 else
662 {
abeeff98
LM
663 if (rocm_event_pipe[0] == -1)
664 return;
665
36f3baab
LM
666 delete_file_handler (rocm_event_pipe[0]);
667
abeeff98
LM
668 ::close (rocm_event_pipe[0]);
669 ::close (rocm_event_pipe[1]);
670 rocm_event_pipe[0] = -1;
671 rocm_event_pipe[1] = -1;
672 }
673}
674
675static void
676rocm_process_one_event (amd_dbgapi_event_id_t event_id,
677 amd_dbgapi_event_kind_t event_kind)
678{
679 struct rocm_inferior_info *info = get_rocm_inferior_info ();
680 amd_dbgapi_process_id_t process_id = info->process_id;
681 amd_dbgapi_status_t status;
682
683 switch (event_kind)
684 {
685 case AMD_DBGAPI_EVENT_KIND_WAVE_STOP:
686 {
687 amd_dbgapi_wave_id_t wave_id;
688 if ((status = amd_dbgapi_event_get_info (process_id, event_id,
689 AMD_DBGAPI_EVENT_INFO_WAVE,
690 sizeof (wave_id), &wave_id))
691 != AMD_DBGAPI_STATUS_SUCCESS)
692 error (_ ("event_get_info for event_%ld failed (rc=%d)"),
693 event_id.handle, status);
694
695 amd_dbgapi_wave_stop_reason_t stop_reason;
696 status = amd_dbgapi_wave_get_info (process_id, wave_id,
697 AMD_DBGAPI_WAVE_INFO_STOP_REASON,
698 sizeof (stop_reason), &stop_reason);
699
700 if (status != AMD_DBGAPI_STATUS_SUCCESS
701 && status != AMD_DBGAPI_STATUS_ERROR_INVALID_WAVE_ID)
702 error (_ ("wave_get_info for wave_%ld failed (rc=%d)"),
703 wave_id.handle, status);
704
705 /* The wave may have exited, or the queue went into an error
706 state. In such cases, we will see another wave command
707 terminated event, and handle the wave termination then. */
708
709 if (status == AMD_DBGAPI_STATUS_SUCCESS)
710 info->wave_stop_events.emplace_back (
711 std::make_pair (wave_id, stop_reason));
712 }
713 break;
714
715 case AMD_DBGAPI_EVENT_KIND_CODE_OBJECT_LIST_UPDATED:
716 amd_dbgapi_code_object_list_updated.notify ();
717 break;
718
719 case AMD_DBGAPI_EVENT_KIND_BREAKPOINT_RESUME:
720 /* Breakpoint resume events should be handled by the breakpoint
721 action, and this code should not reach this. */
722 gdb_assert_not_reached (_ ("unhandled event kind"));
723 break;
724
725 case AMD_DBGAPI_EVENT_KIND_RUNTIME:
726 {
727 amd_dbgapi_runtime_state_t runtime_state;
728
729 if ((status = amd_dbgapi_event_get_info (
730 process_id, event_id, AMD_DBGAPI_EVENT_INFO_RUNTIME_STATE,
731 sizeof (runtime_state), &runtime_state))
732 != AMD_DBGAPI_STATUS_SUCCESS)
733 error (_ ("event_get_info for event_%ld failed (rc=%d)"),
734 event_id.handle, status);
735
736 switch (runtime_state)
737 {
738 case AMD_DBGAPI_RUNTIME_STATE_LOADED_SUPPORTED:
739 amd_dbgapi_activated.notify ();
740 break;
741 case AMD_DBGAPI_RUNTIME_STATE_LOADED_UNSUPPORTED:
742 warning (_ ("ROCm-GDB: low-level runtime version not supported"));
743 break;
744
745 case AMD_DBGAPI_RUNTIME_STATE_UNLOADED:
746 amd_dbgapi_deactivated.notify ();
747 break;
748 }
749 }
750 break;
751
752 default:
753 error (_ ("event kind (%d) not supported"), event_kind);
754 }
755
756 amd_dbgapi_event_processed (process_id, event_id);
757}
758
759/* Drain the amd_dbgapi event queue until an event of the given type is seen.
760 If no particular event kind is specified (AMD_DBGAPI_EVENT_KIND_NONE), the
761 event queue is completely drained. Wave stop events that are not returned
762 are re-queued into the current's process pending wave events. */
763static amd_dbgapi_event_id_t
764rocm_process_event_queue (amd_dbgapi_event_kind_t until_event_kind)
765{
766 struct rocm_inferior_info *info = get_rocm_inferior_info ();
767
768 while (true)
769 {
770 amd_dbgapi_event_id_t event_id;
771 amd_dbgapi_event_kind_t event_kind;
772
773 amd_dbgapi_status_t status = amd_dbgapi_next_pending_event (
774 info->process_id, &event_id, &event_kind);
775
776 if (status != AMD_DBGAPI_STATUS_SUCCESS)
777 error (_ ("next_pending_event failed (rc=%d)"), status);
778
779 if (event_id.handle == AMD_DBGAPI_EVENT_NONE.handle
780 || event_kind == until_event_kind)
781 return event_id;
782
783 rocm_process_one_event (event_id, event_kind);
784 }
785}
786
787ptid_t
788rocm_target_ops::wait (ptid_t ptid, struct target_waitstatus *ws,
789 int target_options)
790{
791 if (debug_infrun)
792 fprintf_unfiltered (gdb_stdlog,
793 "\e[1;34minfrun: rocm_target_ops::wait\e[0m\n");
794
795 if (!ptid_is_gpu (ptid))
796 {
797 ptid_t event_ptid = beneath ()->wait (ptid, ws, target_options);
798 if (event_ptid != minus_one_ptid)
799 return event_ptid;
800 }
801
802 struct rocm_inferior_info *info = get_rocm_inferior_info ();
803 amd_dbgapi_process_id_t process_id = info->process_id;
804
805 /* Drain all the events from the amd_dbgapi, and preserve the ordering. */
806 if (info->wave_stop_events.empty ())
807 {
808 amd_dbgapi_process_set_progress (process_id,
809 AMD_DBGAPI_PROGRESS_NO_FORWARD);
810
811 /* Flush the async file first. */
812 if (target_is_async_p ())
813 async_file_flush ();
814
815 rocm_process_event_queue ();
816
817 /* In all-stop mode, unless the event queue is empty (spurious wake-up),
818 we can keep the process in progress_no_forward mode. The infrun loop
819 will enable forward progress when a thread is resumed. */
820 if (non_stop || info->wave_stop_events.empty ())
821 amd_dbgapi_process_set_progress (process_id,
822 AMD_DBGAPI_PROGRESS_NORMAL);
823 }
824
825 if (info->wave_stop_events.empty ())
826 return minus_one_ptid;
827
828 amd_dbgapi_wave_id_t event_wave_id;
829 amd_dbgapi_wave_stop_reason_t stop_reason;
830
831 std::tie (event_wave_id, stop_reason) = info->wave_stop_events.front ();
832 info->wave_stop_events.pop_front ();
833
834 ptid_t event_ptid (current_inferior ()->pid, 1, event_wave_id.handle);
835
836 if (!find_thread_ptid (event_ptid))
837 {
838 add_thread_silent (event_ptid);
839 set_running (event_ptid, 1);
840 set_executing (event_ptid, 1);
841 }
842
843 /* Since we are manipulating the register cache for the event thread,
844 make sure it is the current thread. */
845 switch_to_thread (event_ptid);
846
847 /* By caching the PC now, we avoid having to suspend/resume the queue
848 later when we need to access it. */
849 amd_dbgapi_global_address_t stop_pc;
850 if (amd_dbgapi_wave_get_info (process_id, event_wave_id,
851 AMD_DBGAPI_WAVE_INFO_PC, sizeof (stop_pc),
852 &stop_pc)
853 == AMD_DBGAPI_STATUS_SUCCESS)
854 {
855 struct regcache *regcache = get_thread_regcache (event_ptid);
856 regcache->raw_supply (gdbarch_pc_regnum (regcache->arch ()), &stop_pc);
857 }
858 ws->kind = TARGET_WAITKIND_STOPPED;
859
860 if (stop_reason
861 & (AMD_DBGAPI_WAVE_STOP_REASON_BREAKPOINT
862 | AMD_DBGAPI_WAVE_STOP_REASON_SINGLE_STEP))
863 ws->value.sig = GDB_SIGNAL_TRAP;
864 else if (stop_reason & AMD_DBGAPI_WAVE_STOP_REASON_MEMORY_VIOLATION)
865 ws->value.sig = GDB_SIGNAL_SEGV;
866 else if (stop_reason
867 & (AMD_DBGAPI_WAVE_STOP_REASON_FP_INPUT_DENORMAL
868 | AMD_DBGAPI_WAVE_STOP_REASON_FP_DIVIDE_BY_0
869 | AMD_DBGAPI_WAVE_STOP_REASON_FP_OVERFLOW
870 | AMD_DBGAPI_WAVE_STOP_REASON_FP_UNDERFLOW
871 | AMD_DBGAPI_WAVE_STOP_REASON_FP_INEXACT
872 | AMD_DBGAPI_WAVE_STOP_REASON_FP_INVALID_OPERATION
873 | AMD_DBGAPI_WAVE_STOP_REASON_INT_DIVIDE_BY_0))
874 ws->value.sig = GDB_SIGNAL_FPE;
875 else
876 ws->value.sig = GDB_SIGNAL_0;
877
878 /* If there are more events in the list, mark the async file so that
879 rocm_target_ops::wait gets called again. */
880 if (target_is_async_p () && !info->wave_stop_events.empty ())
881 async_file_mark ();
882
883 return event_ptid;
884}
885
886bool
887rocm_target_ops::stopped_by_sw_breakpoint ()
888{
889 if (!ptid_is_gpu (inferior_ptid))
890 return beneath ()->supports_stopped_by_sw_breakpoint ()
891 && beneath ()->stopped_by_sw_breakpoint ();
892
893 /* FIXME: we should check that the wave is not single-stepping. */
894
895 struct regcache *regcache = get_thread_regcache (inferior_ptid);
896
897 CORE_ADDR bkpt_pc = regcache_read_pc (regcache)
898 - gdbarch_decr_pc_after_break (regcache->arch ());
899
900 return software_breakpoint_inserted_here_p (regcache->aspace (), bkpt_pc);
901}
902
36f3baab
LM
903void
904rocm_target_ops::close ()
905{
906 /* Unregister from the event loop. */
907 async (0);
908 beneath ()->close ();
909}
910
abeeff98
LM
911void
912rocm_target_ops::mourn_inferior ()
913{
914 /* FIXME: only unpush on the last activation. */
915 /* Disengage the ROCm target_ops. */
916 unpush_target (&rocm_ops);
917
918 beneath ()->mourn_inferior ();
919}
920
921void
922rocm_target_ops::fetch_registers (struct regcache *regcache, int regno)
923{
924 struct gdbarch *gdbarch = regcache->arch ();
925 struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
926
927 /* delegate to the host routines when not on the device */
928
929 if (!rocm_is_amdgcn_gdbarch (gdbarch))
930 {
931 beneath ()->fetch_registers (regcache, regno);
932 return;
933 }
934
935 inferior *inf = find_inferior_ptid (regcache->ptid ());
936 amd_dbgapi_process_id_t process_id = get_amd_dbgapi_process_id (inf);
937 amd_dbgapi_wave_id_t wave_id = get_amd_dbgapi_wave_id (regcache->ptid ());
938
939 gdb_byte raw[AMDGCN_MAX_REGISTER_SIZE];
940
941 amd_dbgapi_status_t status = amd_dbgapi_read_register (
942 process_id, wave_id, tdep->register_ids[regno], 0,
943 TYPE_LENGTH (register_type (gdbarch, regno)), raw);
944
945 if (status == AMD_DBGAPI_STATUS_SUCCESS)
946 {
947 regcache->raw_supply (regno, raw);
948 }
949 else if (status != AMD_DBGAPI_STATUS_ERROR_INVALID_REGISTER_ID)
950 {
951 warning (_ ("Couldn't read register %s (#%d)."),
952 gdbarch_register_name (gdbarch, regno), regno);
953 }
954}
955
956void
957rocm_target_ops::store_registers (struct regcache *regcache, int regno)
958{
959 struct gdbarch *gdbarch = regcache->arch ();
960 struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
961 gdb_byte raw[AMDGCN_MAX_REGISTER_SIZE];
962
963 if (!rocm_is_amdgcn_gdbarch (gdbarch))
964 {
965 beneath ()->store_registers (regcache, regno);
966 return;
967 }
968
969 inferior *inf = find_inferior_ptid (regcache->ptid ());
970 amd_dbgapi_process_id_t process_id = get_amd_dbgapi_process_id (inf);
971 amd_dbgapi_wave_id_t wave_id = get_amd_dbgapi_wave_id (regcache->ptid ());
972
973 regcache->raw_collect (regno, &raw);
974
975 amd_dbgapi_status_t status = amd_dbgapi_write_register (
976 process_id, wave_id, tdep->register_ids[regno], 0,
977 TYPE_LENGTH (register_type (gdbarch, regno)), raw);
978
979 if (status != AMD_DBGAPI_STATUS_SUCCESS)
980 {
981 warning (_ ("Couldn't write register %s (#%d)."),
982 gdbarch_register_name (gdbarch, regno), regno);
983 }
984}
985
986/* Fix breakpoints created with an address location while the
987 architecture was set to the host (could be fixed in core GDB). */
988
989static void
990rocm_target_breakpoint_fixup (struct breakpoint *b)
991{
992 if (b->location.get ()
993 && event_location_type (b->location.get ()) == ADDRESS_LOCATION
994 && gdbarch_bfd_arch_info (b->loc->gdbarch)->arch == bfd_arch_amdgcn
995 && gdbarch_bfd_arch_info (b->gdbarch)->arch != bfd_arch_amdgcn)
996 {
997 b->gdbarch = b->loc->gdbarch;
998 }
999}
1000
1001struct gdbarch *
1002rocm_target_ops::thread_architecture (ptid_t ptid)
1003{
1004 static std::result_of<decltype (&ptid_t::tid) (ptid_t)>::type last_tid = 0;
1005 static struct gdbarch *cached_arch = nullptr;
1006
1007 if (!ptid_is_gpu (ptid))
1008 return beneath ()->thread_architecture (ptid);
1009
1010 /* We can cache the gdbarch for a given wave_id (ptid::tid) because
1011 wave IDs are unique, and aren't reused. */
1012 if (ptid.tid () == last_tid)
1013 return cached_arch;
1014
1015 amd_dbgapi_process_id_t process_id = get_amd_dbgapi_process_id ();
1016 amd_dbgapi_wave_id_t wave_id = get_amd_dbgapi_wave_id (ptid);
1017 amd_dbgapi_architecture_id_t architecture_id;
1018
1019 if (amd_dbgapi_wave_get_info (process_id, wave_id,
1020 AMD_DBGAPI_WAVE_INFO_ARCHITECTURE,
1021 sizeof (architecture_id), &architecture_id)
1022 != AMD_DBGAPI_STATUS_SUCCESS)
1023 error (_ ("Couldn't get architecture for wave_%ld"), ptid.tid ());
1024
1025 uint32_t elf_amdgpu_machine;
1026 if (amd_dbgapi_architecture_get_info (
1027 architecture_id, AMD_DBGAPI_ARCHITECTURE_INFO_ELF_AMDGPU_MACHINE,
1028 sizeof (elf_amdgpu_machine), &elf_amdgpu_machine)
1029 != AMD_DBGAPI_STATUS_SUCCESS)
1030 error (_ ("Couldn't get elf_amdgpu_machine for architecture_%ld"),
1031 architecture_id.handle);
1032
1033 struct gdbarch_info info;
1034 gdbarch_info_init (&info);
1035
1036 info.bfd_arch_info = bfd_lookup_arch (bfd_arch_amdgcn, elf_amdgpu_machine);
1037 info.byte_order = BFD_ENDIAN_LITTLE;
1038 info.osabi = GDB_OSABI_AMDGPU_HSA;
1039
1040 last_tid = ptid.tid ();
1041 if (!(cached_arch = gdbarch_find_by_info (info)))
1042 error (_ ("Couldn't get elf_amdgpu_machine (%#x)"), elf_amdgpu_machine);
1043
1044 return cached_arch;
1045}
1046
1047void
1048rocm_target_ops::update_thread_list ()
1049{
1050 for (inferior *inf : all_inferiors ())
1051 {
9e275233 1052 amd_dbgapi_process_id_t process_id;
abeeff98
LM
1053 amd_dbgapi_wave_id_t *wave_list;
1054 size_t count;
1055
9e275233
LM
1056 process_id = get_amd_dbgapi_process_id (inf);
1057 if (process_id.handle == AMD_DBGAPI_PROCESS_NONE.handle)
1058 {
1059 /* The inferior may not be attached yet. */
1060 continue;
1061 }
1062
abeeff98
LM
1063 amd_dbgapi_changed_t changed;
1064 amd_dbgapi_status_t status;
1065 if ((status
1066 = amd_dbgapi_wave_list (process_id, &count, &wave_list, &changed))
1067 != AMD_DBGAPI_STATUS_SUCCESS)
9e275233 1068 error (_ ("amd_dbgapi_wave_list failed (rc=%d)"), status);
abeeff98
LM
1069
1070 if (changed == AMD_DBGAPI_CHANGED_NO)
1071 continue;
1072
1073 /* Create a set and free the wave list. */
1074 std::set<std::result_of<decltype (&ptid_t::tid) (ptid_t)>::type> threads;
1075 for (size_t i = 0; i < count; ++i)
1076 threads.emplace (wave_list[i].handle);
1077 xfree (wave_list);
1078
1079 /* Then prune the wave_ids that already have a thread_info. */
1080 for (thread_info *tp : inf->non_exited_threads ())
1081 if (ptid_is_gpu (tp->ptid))
1082 threads.erase (tp->ptid.tid ());
1083
1084 /* The wave_ids that are left require a new thread_info. */
1085 for (auto &&tid : threads)
1086 {
1087 ptid_t wave_ptid (inf->pid, 1, tid);
9e275233 1088 /* FIXME: is this really needed?
abeeff98
LM
1089 amd_dbgapi_wave_state_t state;
1090
1091 if (amd_dbgapi_wave_get_info (
1092 process_id, get_amd_dbgapi_wave_id (wave_ptid),
1093 AMD_DBGAPI_WAVE_INFO_STATE, sizeof (state), &state)
1094 != AMD_DBGAPI_STATUS_SUCCESS)
9e275233 1095 continue;*/
abeeff98
LM
1096
1097 add_thread_silent (wave_ptid);
1098 set_running (wave_ptid, 1);
1099 set_executing (wave_ptid, 1);
1100 }
1101 }
1102
1103 /* Give the beneath target a chance to do extra processing. */
1104 this->beneath ()->update_thread_list ();
1105}
1106
1107static void
1108rocm_target_solib_loaded (struct so_list *solib)
1109{
1110 /* Notify the amd_dbgapi that a shared library has been loaded. */
1111 for (auto &&value : get_rocm_inferior_info ()->notify_solib_map)
1112 /* TODO: If we want to support file name wildcards, change this code. */
1113 if (::strstr (solib->so_original_name, value.second.compare.c_str ())
1114 && !value.second.is_loaded)
1115 {
1116 value.second.solib = solib;
1117 value.second.is_loaded = true;
1118
1119 amd_dbgapi_report_shared_library (
1120 get_amd_dbgapi_process_id (),
1121 amd_dbgapi_shared_library_id_t{ value.first },
1122 AMD_DBGAPI_SHARED_LIBRARY_STATE_LOADED);
1123 }
1124}
1125
1126static void
1127rocm_target_solib_unloaded (struct so_list *solib)
1128{
1129 /* Notify the amd_dbgapi that a shared library will unload. */
1130 for (auto &&value : get_rocm_inferior_info ()->notify_solib_map)
1131 /* TODO: If we want to support file name wildcards, change this code. */
1132 if (::strstr (solib->so_original_name, value.second.compare.c_str ())
1133 && value.second.is_loaded)
1134 {
1135 struct rocm_inferior_info *info = get_rocm_inferior_info ();
1136
1137 amd_dbgapi_report_shared_library (
1138 info->process_id, amd_dbgapi_shared_library_id_t{ value.first },
1139 AMD_DBGAPI_SHARED_LIBRARY_STATE_UNLOADED);
1140
1141 /* Delete breakpoints that were left inserted in this shared library.
1142 */
1143 for (auto it = info->breakpoint_map.begin ();
1144 it != info->breakpoint_map.end ();)
1145 if (solib_contains_address_p (solib, it->second->loc->address))
1146 {
1147 warning (_ ("breakpoint_%ld is still inserted after "
1148 "shared_library_%ld was unloaded"),
1149 it->first, value.first);
1150 delete_breakpoint (it->second);
1151 it = info->breakpoint_map.erase (it);
1152 }
1153 else
1154 ++it;
1155
1156 value.second.solib = nullptr;
1157 value.second.is_loaded = false;
1158 }
1159}
1160
1161static void
1162rocm_target_inferior_created (struct target_ops *target, int from_tty)
1163{
1164 struct inferior *inf = current_inferior ();
1165 auto *info = get_rocm_inferior_info (inf);
1166 amd_dbgapi_status_t status;
1167
1168 if (!target_can_async_p ())
1169 {
1170 warning (
1171 _ ("ROCm-GDB requires target-async, GPU debugging is disabled"));
1172 return;
1173 }
1174
1175 gdb_assert (info->wave_stop_events.empty ());
1176
1177 status = amd_dbgapi_process_attach (inf, &info->process_id);
1178
1179 if (status == AMD_DBGAPI_STATUS_ERROR_VERSION_MISMATCH)
1180 warning (_ ("The version of the kernel driver does not match the version "
1181 "required by the ROCm debugger library"));
1182
1183 if (status != AMD_DBGAPI_STATUS_SUCCESS)
1184 {
1185 warning (_ ("Could not attach to process %d"), inf->pid);
1186 return;
1187 }
1188
1189 if (amd_dbgapi_process_get_info (info->process_id,
1190 AMD_DBGAPI_PROCESS_INFO_NOTIFIER,
1191 sizeof (info->notifier), &info->notifier)
1192 != AMD_DBGAPI_STATUS_SUCCESS)
1193 {
1194 warning (_ ("Could not retrieve process %d's notifier"), inf->pid);
1195 amd_dbgapi_process_detach (info->process_id);
1196 return;
1197 }
1198
1199 /* We add a file handler for events returned by the debugger api. We'll use
1200 this handler to signal our async handler that events are available. */
1201 add_file_handler (
1202 info->notifier,
1203 [] (int error, gdb_client_data client_data) {
1204 auto info_ = static_cast<struct rocm_inferior_info *> (client_data);
1205 int ret;
1206
1207 /* Drain the notifier pipe. */
1208 do
1209 {
1210 char buf;
1211 ret = read (info_->notifier, &buf, 1);
1212 }
1213 while (ret >= 0 || (ret == -1 && errno == EINTR));
1214
1215 /* Signal our async handler. */
1216 async_file_mark ();
1217 },
1218 info);
1219
1220 /* Attaching to the inferior may have generated runtime events, process
1221 them now. */
1222 rocm_process_event_queue ();
1223}
1224
1225static void
1226rocm_target_inferior_exit (struct inferior *inf)
1227{
1228 auto *info = get_rocm_inferior_info (inf);
243f18ba 1229 info->has_exited = true;
abeeff98
LM
1230
1231 amd_dbgapi_deactivated.notify ();
1232
b8ff49b7
LM
1233 if (info->notifier != -1)
1234 delete_file_handler (info->notifier);
abeeff98
LM
1235
1236 amd_dbgapi_process_detach (info->process_id);
1237
1238 /* Delete the breakpoints that are still active. */
1239 for (auto &&value : info->breakpoint_map)
1240 delete_breakpoint (value.second);
1241
1242 rocm_inferior_data.clear (inf);
1243}
1244
1245static cli_style_option warning_style ("rocm_warning", ui_file_style::RED);
1246static cli_style_option info_style ("rocm_info", ui_file_style::GREEN);
1247static cli_style_option verbose_style ("rocm_verbose", ui_file_style::BLUE);
1248
1249static amd_dbgapi_callbacks_t dbgapi_callbacks = {
1250 /* allocate_memory. */
0cf995bc 1251 .allocate_memory = malloc,
abeeff98
LM
1252
1253 /* deallocate_memory. */
0cf995bc 1254 .deallocate_memory = free,
abeeff98
LM
1255
1256 /* get_os_pid. */
1257 .get_os_pid = [] (amd_dbgapi_client_process_id_t client_process_id,
1258 pid_t *pid) -> amd_dbgapi_status_t {
1259 inferior *inf = static_cast<inferior *> (client_process_id);
243f18ba
LM
1260 struct rocm_inferior_info *info = get_rocm_inferior_info (inf);
1261
1262 if (info->has_exited)
1263 return AMD_DBGAPI_STATUS_ERROR_PROCESS_EXITED;
abeeff98
LM
1264
1265 *pid = inf->pid;
1266 return AMD_DBGAPI_STATUS_SUCCESS;
1267 },
1268
1269 /* enable_notify_shared_library callback. */
1270 .enable_notify_shared_library
1271 = [] (amd_dbgapi_client_process_id_t client_process_id,
1272 const char *library_name, amd_dbgapi_shared_library_id_t library_id,
1273 amd_dbgapi_shared_library_state_t *library_state)
1274 -> amd_dbgapi_status_t {
1275 inferior *inf = static_cast<inferior *> (client_process_id);
1276 struct rocm_inferior_info *info = get_rocm_inferior_info (inf);
1277
1278 if (!library_name || !library_state)
1279 return AMD_DBGAPI_STATUS_ERROR_INVALID_ARGUMENT;
1280
1281 if (info->notify_solib_map.find (library_id.handle)
1282 != info->notify_solib_map.end ())
1283 {
1284 /* This library id is already registered. */
1285 return AMD_DBGAPI_STATUS_ERROR;
1286 }
1287
1288 /* Check whether the library is already loaded. */
1289 bool is_loaded = false;
1290 struct so_list *solib;
1291 for (solib = inf->pspace->so_list; solib; solib = solib->next)
1292 if (::strstr (solib->so_original_name, library_name))
1293 {
1294 is_loaded = true;
1295 break;
1296 }
1297
1298 /* Check that the library_name is valid. If must not be empty, and
1299 should not have wildcard characters. */
1300 if (*library_name == '\0'
1301 || std::string (library_name).find_first_of ("*?[]")
1302 != std::string::npos)
1303 return AMD_DBGAPI_STATUS_ERROR_INVALID_ARGUMENT;
1304
1305 /* Add a new entry in the notify_solib_map. */
1306 if (!info->notify_solib_map
1307 .emplace (std::piecewise_construct,
1308 std::forward_as_tuple (library_id.handle),
1309 std::forward_as_tuple (rocm_notify_shared_library_info{
1310 library_name, solib, is_loaded }))
1311 .second)
1312 return AMD_DBGAPI_STATUS_ERROR;
1313
1314 *library_state = is_loaded ? AMD_DBGAPI_SHARED_LIBRARY_STATE_LOADED
1315 : AMD_DBGAPI_SHARED_LIBRARY_STATE_UNLOADED;
1316
1317 return AMD_DBGAPI_STATUS_SUCCESS;
1318 },
1319
1320 /* disable_notify_shared_library callback. */
1321 .disable_notify_shared_library
1322 = [] (amd_dbgapi_client_process_id_t client_process_id,
1323 amd_dbgapi_shared_library_id_t library_id) -> amd_dbgapi_status_t {
1324 inferior *inf = static_cast<inferior *> (client_process_id);
1325 struct rocm_inferior_info *info = get_rocm_inferior_info (inf);
1326
1327 auto it = info->notify_solib_map.find (library_id.handle);
1328 if (it == info->notify_solib_map.end ())
1329 return AMD_DBGAPI_STATUS_ERROR_INVALID_SHARED_LIBRARY_ID;
1330
1331 info->notify_solib_map.erase (it);
1332 return AMD_DBGAPI_STATUS_SUCCESS;
1333 },
1334
1335 /* get_symbol_address callback. */
1336 .get_symbol_address =
1337 [] (amd_dbgapi_client_process_id_t client_process_id,
1338 amd_dbgapi_shared_library_id_t library_id, const char *symbol_name,
1339 amd_dbgapi_global_address_t *address) {
1340 inferior *inf = static_cast<inferior *> (client_process_id);
1341 struct rocm_inferior_info *info = get_rocm_inferior_info (inf);
1342
1343 auto it = info->notify_solib_map.find (library_id.handle);
1344 if (it == info->notify_solib_map.end ())
1345 return AMD_DBGAPI_STATUS_ERROR_INVALID_SHARED_LIBRARY_ID;
1346
1347 struct so_list *solib = it->second.solib;
1348 if (!solib)
1349 return AMD_DBGAPI_STATUS_ERROR_LIBRARY_NOT_LOADED;
1350
1351 solib_read_symbols (solib, 0);
1352 gdb_assert (solib->objfile);
1353
1354 struct bound_minimal_symbol msymbol
1355 = lookup_minimal_symbol (symbol_name, NULL, solib->objfile);
1356
1357 if (!msymbol.minsym || BMSYMBOL_VALUE_ADDRESS (msymbol) == 0)
1358 return AMD_DBGAPI_STATUS_ERROR_SYMBOL_NOT_FOUND;
1359
1360 *address = BMSYMBOL_VALUE_ADDRESS (msymbol);
1361 return AMD_DBGAPI_STATUS_SUCCESS;
1362 },
1363
1364 /* set_breakpoint callback. */
1365 .add_breakpoint =
1366 [] (amd_dbgapi_client_process_id_t client_process_id,
1367 amd_dbgapi_shared_library_id_t shared_library_id,
1368 amd_dbgapi_global_address_t address,
1369 amd_dbgapi_breakpoint_id_t breakpoint_id) {
1370 inferior *inf = static_cast<inferior *> (client_process_id);
1371 struct rocm_inferior_info *info = get_rocm_inferior_info (inf);
1372
1373 /* Initialize the breakpoint ops lazily since we depend on
1374 bkpt_breakpoint_ops and we can't control the order in which
1375 initializers are called. */
1376 if (rocm_breakpoint_ops.check_status == NULL)
1377 {
1378 rocm_breakpoint_ops = bkpt_breakpoint_ops;
1379 rocm_breakpoint_ops.check_status = rocm_breakpoint_check_status;
9e275233 1380 rocm_breakpoint_ops.re_set = rocm_breakpoint_re_set;
abeeff98
LM
1381 }
1382
1383 auto it = info->breakpoint_map.find (breakpoint_id.handle);
1384 if (it != info->breakpoint_map.end ())
1385 return AMD_DBGAPI_STATUS_ERROR_INVALID_BREAKPOINT_ID;
1386
1387 /* Create a new breakpoint. */
1388 struct obj_section *section = find_pc_section (address);
1389 if (!section || !section->objfile)
1390 return AMD_DBGAPI_STATUS_ERROR;
1391
1392 event_location_up location
1393 = new_address_location (address, nullptr, 0);
1394 if (!create_breakpoint (
1395 get_objfile_arch (section->objfile), location.get (),
1396 /*cond_string*/ NULL, /*thread*/ -1, /*extra_sring*/ NULL,
1397 /*parse_extra*/ 0, /*tempflag*/ 0, /*bptype*/ bp_breakpoint,
1398 /*ignore_count*/ 0, /*pending_break*/ AUTO_BOOLEAN_FALSE,
1399 /*ops*/ &rocm_breakpoint_ops, /*from_tty*/ 0,
1400 /*enabled*/ 1, /*internal*/ 1, /*flags*/ 0))
1401 return AMD_DBGAPI_STATUS_ERROR;
1402
1403 /* Find our breakpoint in the breakpoint list. */
1404 auto bp_loc = std::make_pair (inf->aspace, address);
1405 auto bp = breakpoint_find_if (
1406 [] (struct breakpoint *b, void *data) {
1407 auto *arg = static_cast<decltype (&bp_loc)> (data);
1408 if (b->ops == &rocm_breakpoint_ops && b->loc
1409 && b->loc->pspace->aspace == arg->first
1410 && b->loc->address == arg->second)
1411 return 1;
1412 return 0;
1413 },
1414 reinterpret_cast<void *> (&bp_loc));
1415
1416 if (!bp)
1417 error (_ ("Could not find breakpoint"));
1418
1419 info->breakpoint_map.emplace (breakpoint_id.handle, bp);
1420 return AMD_DBGAPI_STATUS_SUCCESS;
1421 },
1422
1423 /* remove_breakpoint callback. */
1424 .remove_breakpoint =
1425 [] (amd_dbgapi_client_process_id_t client_process_id,
1426 amd_dbgapi_breakpoint_id_t breakpoint_id) {
1427 inferior *inf = static_cast<inferior *> (client_process_id);
1428 struct rocm_inferior_info *info = get_rocm_inferior_info (inf);
1429
1430 auto it = info->breakpoint_map.find (breakpoint_id.handle);
1431 if (it == info->breakpoint_map.end ())
1432 return AMD_DBGAPI_STATUS_ERROR_INVALID_BREAKPOINT_ID;
1433
1434 delete_breakpoint (it->second);
1435 info->breakpoint_map.erase (it);
1436
1437 return AMD_DBGAPI_STATUS_SUCCESS;
1438 },
1439
1440 /* set_breakpoint_state callback. */
1441 .set_breakpoint_state =
1442 [] (amd_dbgapi_client_process_id_t client_process_id,
1443 amd_dbgapi_breakpoint_id_t breakpoint_id,
1444 amd_dbgapi_breakpoint_state_t breakpoint_state) {
1445 inferior *inf = static_cast<inferior *> (client_process_id);
1446 struct rocm_inferior_info *info = get_rocm_inferior_info (inf);
1447
1448 auto it = info->breakpoint_map.find (breakpoint_id.handle);
1449 if (it == info->breakpoint_map.end ())
1450 return AMD_DBGAPI_STATUS_ERROR_INVALID_BREAKPOINT_ID;
1451
1452 if (breakpoint_state == AMD_DBGAPI_BREAKPOINT_STATE_ENABLE)
1453 it->second->enable_state = bp_enabled;
1454 else if (breakpoint_state == AMD_DBGAPI_BREAKPOINT_STATE_DISABLE)
1455 it->second->enable_state = bp_disabled;
1456 else
1457 return AMD_DBGAPI_STATUS_ERROR_INVALID_ARGUMENT;
1458
1459 return AMD_DBGAPI_STATUS_SUCCESS;
1460 },
1461
1462 .log_message
1463 = [] (amd_dbgapi_log_level_t level, const char *message) -> void {
1464 gdb::optional<target_terminal::scoped_restore_terminal_state> tstate;
1465
1466 if (level > get_debug_amd_dbgapi_log_level ())
1467 return;
1468
1469 if (target_supports_terminal_ours ())
1470 {
1471 tstate.emplace ();
1472 target_terminal::ours_for_output ();
1473 }
1474
1475 if (filtered_printing_initialized ())
1476 wrap_here ("");
1477
1478 struct ui_file *out_file
1479 = (level >= AMD_DBGAPI_LOG_LEVEL_INFO) ? gdb_stdlog : gdb_stderr;
1480
1481 switch (level)
1482 {
1483 case AMD_DBGAPI_LOG_LEVEL_FATAL_ERROR:
1484 fputs_unfiltered ("[amd-dbgapi]: ", out_file);
1485 break;
1486 case AMD_DBGAPI_LOG_LEVEL_WARNING:
1487 fputs_styled ("[amd-dbgapi]: ", warning_style.style (), out_file);
1488 break;
1489 case AMD_DBGAPI_LOG_LEVEL_INFO:
1490 fputs_styled ("[amd-dbgapi]: ", info_style.style (), out_file);
1491 break;
1492 case AMD_DBGAPI_LOG_LEVEL_VERBOSE:
1493 fputs_styled ("[amd-dbgapi]: ", verbose_style.style (), out_file);
1494 break;
1495 }
1496
1497 fputs_unfiltered (message, out_file);
1498 fputs_unfiltered ("\n", out_file);
1499 }
1500};
1501
1502/* Implementation of `_wave_id' variable. */
1503
1504static struct value *
1505rocm_wave_id_make_value (struct gdbarch *gdbarch, struct internalvar *var,
1506 void *ignore)
1507{
1508 if (ptid_is_gpu (inferior_ptid))
1509 {
1510 amd_dbgapi_process_id_t process_id = get_amd_dbgapi_process_id ();
1511 amd_dbgapi_wave_id_t wave_id = get_amd_dbgapi_wave_id (inferior_ptid);
1512 uint32_t group_ids[3], wave_in_group;
1513
1514 if (amd_dbgapi_wave_get_info (process_id, wave_id,
1515 AMD_DBGAPI_WAVE_INFO_WORK_GROUP_COORD,
1516 sizeof (group_ids), &group_ids)
1517 == AMD_DBGAPI_STATUS_SUCCESS
1518 && amd_dbgapi_wave_get_info (
1519 process_id, wave_id,
1520 AMD_DBGAPI_WAVE_INFO_WAVE_NUMBER_IN_WORK_GROUP,
1521 sizeof (wave_in_group), &wave_in_group)
1522 == AMD_DBGAPI_STATUS_SUCCESS)
1523 {
1524 std::string wave_id_str
1525 = string_printf ("(%d,%d,%d)/%d", group_ids[2], group_ids[1],
1526 group_ids[0], wave_in_group);
1527
1528 return value_cstring (wave_id_str.data (), wave_id_str.length () + 1,
1529 builtin_type (gdbarch)->builtin_char);
1530 }
1531 }
1532
1533 return allocate_value (builtin_type (gdbarch)->builtin_void);
1534}
1535
1536static const struct internalvar_funcs rocm_wave_id_funcs
1537 = { rocm_wave_id_make_value, NULL, NULL };
1538
1539/* List of set/show debug amd_dbgapi commands. */
1540struct cmd_list_element *set_debug_amd_dbgapi_list;
1541struct cmd_list_element *show_debug_amd_dbgapi_list;
1542
1543static void
1544set_debug_amd_dbgapi (const char *arg, int from_tty)
1545{
1546 help_list (set_debug_amd_dbgapi_list, "set debug amd-dbgapi ",
1547 (enum command_class) - 1, gdb_stdout);
1548}
1549
1550static void
1551show_debug_amd_dbgapi (const char *args, int from_tty)
1552{
1553 cmd_show_list (show_debug_amd_dbgapi_list, from_tty, "");
1554}
1555
1556constexpr char amd_dbgapi_log_level_off[] = "off";
1557constexpr char amd_dbgapi_log_level_error[] = "error";
1558constexpr char amd_dbgapi_log_level_warning[] = "warning";
1559constexpr char amd_dbgapi_log_level_info[] = "info";
1560constexpr char amd_dbgapi_log_level_verbose[] = "verbose";
1561
1562constexpr const char *debug_amd_dbgapi_log_level_enums[]
1563 = { [AMD_DBGAPI_LOG_LEVEL_NONE] = amd_dbgapi_log_level_off,
1564 [AMD_DBGAPI_LOG_LEVEL_FATAL_ERROR] = amd_dbgapi_log_level_error,
1565 [AMD_DBGAPI_LOG_LEVEL_WARNING] = amd_dbgapi_log_level_warning,
1566 [AMD_DBGAPI_LOG_LEVEL_INFO] = amd_dbgapi_log_level_info,
1567 [AMD_DBGAPI_LOG_LEVEL_VERBOSE] = amd_dbgapi_log_level_verbose,
1568 nullptr };
1569
1570static const char *debug_amd_dbgapi_log_level = amd_dbgapi_log_level_error;
1571
1572static amd_dbgapi_log_level_t
1573get_debug_amd_dbgapi_log_level ()
1574{
1575 size_t pos;
1576 for (pos = 0; debug_amd_dbgapi_log_level_enums[pos]; ++pos)
1577 if (debug_amd_dbgapi_log_level == debug_amd_dbgapi_log_level_enums[pos])
1578 break;
1579
1580 gdb_assert (debug_amd_dbgapi_log_level_enums[pos]);
1581 return static_cast<amd_dbgapi_log_level_t> (pos);
1582}
1583
1584static void
1585set_debug_amd_dbgapi_log_level (const char *args, int from_tty,
1586 struct cmd_list_element *c)
1587{
1588 amd_dbgapi_set_log_level (get_debug_amd_dbgapi_log_level ());
1589}
1590
1591static void
1592show_debug_amd_dbgapi_log_level (struct ui_file *file, int from_tty,
1593 struct cmd_list_element *c,
1594 const char *value)
1595{
1596 fprintf_filtered (file, _ ("The amd-dbgapi log level is %s.\n"), value);
1597}
1598
1599static void
1600info_agents_command (const char *args, int from_tty)
1601{
1602 amd_dbgapi_process_id_t process_id = get_amd_dbgapi_process_id ();
1603 struct ui_out *uiout = current_uiout;
1604 amd_dbgapi_status_t status;
1605
1606 amd_dbgapi_agent_id_t *agent_list;
1607 size_t count = 0;
1608
1609 if (process_id.handle != AMD_DBGAPI_PROCESS_NONE.handle
1610 && (status
1611 = amd_dbgapi_agent_list (process_id, &count, &agent_list, nullptr))
1612 != AMD_DBGAPI_STATUS_SUCCESS)
1613 error (_ ("amd_dbgapi_agent_list failed (rc=%d)"), status);
1614
1615 if (!count && !uiout->is_mi_like_p ())
1616 {
1617 uiout->field_string (NULL,
1618 _ ("No agents are currently active.\n"));
1619 return;
1620 }
1621
1622 /* Calculate the maximum size needed to print the agents names. */
1623 std::vector<std::string> agent_names (count);
1624
1625 size_t max_name_len = 0;
1626 for (size_t i = 0; i < count; ++i)
1627 {
1628 char *agent_name;
1629
1630 if ((status = amd_dbgapi_agent_get_info (
1631 process_id, agent_list[i], AMD_DBGAPI_AGENT_INFO_NAME,
1632 sizeof (agent_name), &agent_name))
1633 != AMD_DBGAPI_STATUS_SUCCESS)
1634 {
1635 if (status == AMD_DBGAPI_STATUS_ERROR_INVALID_AGENT_ID)
1636 agent_names[i] = "N/A";
1637 else
1638 error (_ ("amd_dbgapi_agent_get_info failed (rc=%d"), status);
1639 }
1640 else
1641 {
1642 agent_names[i] = agent_name;
1643 xfree (agent_name);
1644 }
1645
1646 max_name_len = std::max (max_name_len, agent_names[i].size ());
1647 }
1648
1649 /* Header: */
1650 ui_out_emit_table table_emmitter (uiout, 7, count, "InfoRocmDevicesTable");
1651
1652 uiout->table_header (2, ui_left, "agent_id", "Id");
1653 uiout->table_header (8, ui_left, "location_id", "PCI Slot");
1654 uiout->table_header (std::max (11ul, max_name_len), ui_left, "name",
1655 "Device Name");
1656 uiout->table_header (14, ui_left, "num_se", "Shader Engines");
1657 uiout->table_header (13, ui_left, "num_cu", "Compute Units");
1658 uiout->table_header (7, ui_left, "simd", "SIMD/CU");
1659 uiout->table_header (15, ui_left, "waves", "Wavefronts/SIMD");
1660 uiout->table_body ();
1661
1662 /* Rows: */
1663 for (size_t i = 0; i < count; ++i)
1664 {
1665 ui_out_emit_tuple tuple_emitter (uiout, "InfoRocmDevicesRow");
1666
1667 /* agent */
1668 uiout->field_signed ("agent_id", agent_list[i].handle);
1669
1670 /* location */
1671 uint32_t location_id;
1672 if ((status = amd_dbgapi_agent_get_info (
1673 process_id, agent_list[i], AMD_DBGAPI_AGENT_INFO_PCIE_SLOT,
1674 sizeof (location_id), &location_id))
1675 != AMD_DBGAPI_STATUS_SUCCESS)
1676 {
1677 if (status == AMD_DBGAPI_STATUS_ERROR_INVALID_AGENT_ID)
1678 uiout->field_string ("location_id", "N/A");
1679 else
1680 error (_ ("amd_dbgapi_agent_get_info failed (rc=%d"), status);
1681 }
1682 else
1683 uiout->field_string (
1684 "location_id",
1685 string_printf ("%02x:%02x.%d", (location_id >> 8) & 0xFF,
1686 (location_id >> 3) & 0x1F, location_id & 0x7));
1687
1688 /* name */
1689 uiout->field_string ("name", agent_names[i]);
1690
1691 /* num_se, num_cu, simd, waves */
1692
1693#define UIOUT_FIELD_INT(name, query) \
1694 uint32_t name; \
1695 if ((status = amd_dbgapi_agent_get_info (process_id, agent_list[i], query, \
1696 sizeof (name), &name)) \
1697 != AMD_DBGAPI_STATUS_SUCCESS) \
1698 { \
1699 if (status == AMD_DBGAPI_STATUS_ERROR_INVALID_AGENT_ID) \
1700 uiout->field_string (#name, "N/A"); \
1701 else \
1702 error (_ ("amd_dbgapi_agent_get_info failed (rc=%d"), status); \
1703 } \
1704 else \
1705 uiout->field_signed (#name, name);
1706
1707 UIOUT_FIELD_INT (num_se, AMD_DBGAPI_AGENT_INFO_SHADER_ENGINE_COUNT);
1708 UIOUT_FIELD_INT (num_cu, AMD_DBGAPI_AGENT_INFO_COMPUTE_UNIT_COUNT);
1709 UIOUT_FIELD_INT (simd, AMD_DBGAPI_AGENT_INFO_NUM_SIMD_PER_COMPUTE_UNIT);
1710 UIOUT_FIELD_INT (waves, AMD_DBGAPI_AGENT_INFO_MAX_WAVES_PER_SIMD);
1711
1712#undef UIOUT_FIELD_INT
1713
1714 uiout->text ("\n");
1715 }
1716
1717 xfree (agent_list);
1718 gdb_flush (gdb_stdout);
1719}
1720
1721/* -Wmissing-prototypes */
1722extern initialize_file_ftype _initialize_rocm_tdep;
1723
1724void
1725_initialize_rocm_tdep (void)
1726{
48e5c3f7
LM
1727 /* Make sure the loaded debugger library version is greater than or equal to
1728 the one used to build ROCgdb. */
1729 uint32_t major, minor, patch;
1730 amd_dbgapi_get_version (&major, &minor, &patch);
1731 if (major != AMD_DBGAPI_VERSION_MAJOR || minor < AMD_DBGAPI_VERSION_MINOR)
1732 error (
1733 _ ("amd-dbgapi library version mismatch, got %d.%d.%d, need %d.%d+"),
1734 major, minor, patch, AMD_DBGAPI_VERSION_MAJOR,
1735 AMD_DBGAPI_VERSION_MINOR);
1736
abeeff98 1737 /* Initialize the ROCm Debug API. */
48e5c3f7
LM
1738 amd_dbgapi_status_t status = amd_dbgapi_initialize (&dbgapi_callbacks);
1739 if (status != AMD_DBGAPI_STATUS_SUCCESS)
1740 error (_ ("amd-dbgapi failed to initialize (rc=%d)"), status);
abeeff98
LM
1741
1742 /* Set the initial log level. */
1743 amd_dbgapi_set_log_level (get_debug_amd_dbgapi_log_level ());
1744
1745 /* Install observers. */
1746 gdb::observers::breakpoint_created.attach (rocm_target_breakpoint_fixup);
1747 gdb::observers::solib_loaded.attach (rocm_target_solib_loaded);
1748 gdb::observers::solib_unloaded.attach (rocm_target_solib_unloaded);
1749 gdb::observers::inferior_created.attach (rocm_target_inferior_created);
1750 gdb::observers::inferior_exit.attach (rocm_target_inferior_exit);
1751
1752 amd_dbgapi_activated.attach (rocm_target_dbgapi_activated);
1753 amd_dbgapi_deactivated.attach (rocm_target_dbgapi_deactivated);
1754
1755 create_internalvar_type_lazy ("_wave_id", &rocm_wave_id_funcs, NULL);
1756
1757 add_prefix_cmd (
1758 "amd-dbgapi", no_class, set_debug_amd_dbgapi,
1759 _ ("Generic command for setting amd-dbgapi debugging flags"),
1760 &set_debug_amd_dbgapi_list, "set debug amd-dbgapi ", 0, &setdebuglist);
1761
1762 add_prefix_cmd (
1763 "amd-dbgapi", no_class, show_debug_amd_dbgapi,
1764 _ ("Generic command for showing amd-dbgapi debugging flags"),
1765 &show_debug_amd_dbgapi_list, "show debug amd-dbgapi ", 0,
1766 &showdebuglist);
1767
1768 add_setshow_enum_cmd (
1769 "log-level", class_maintenance, debug_amd_dbgapi_log_level_enums,
1770 &debug_amd_dbgapi_log_level, _ ("Set the amd-dbgapi log level."),
1771 _ ("Show the amd-dbgapi log level."),
1772 _ ("off == no logging is enabled\n"
1773 "error == fatal errors are reported\n"
1774 "warning == fatal errors and warnings are reported\n"
1775 "info == fatal errors, warnings, and info messages are reported\n"
1776 "verbose == all messages are reported"),
1777 set_debug_amd_dbgapi_log_level, show_debug_amd_dbgapi_log_level,
1778 &set_debug_amd_dbgapi_list, &show_debug_amd_dbgapi_list);
1779
1780 add_cmd ("agents", class_info, info_agents_command,
1781 _ ("Info about currently active agents."), &infolist);
1782}
This page took 0.087504 seconds and 4 git commands to generate.