blob: 14cc614961ab2a30089a6f02116e180bbf319dc2 [file]
/* Host dependent utilities for the amd-dbgapi target on MinGW.
Copyright (C) 2024-2026 Free Software Foundation, Inc.
This file is part of GDB.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include "amd-dbgapi-hdep.h"
#include <amd-dbgapi/amd-dbgapi.h>
#include <winsock2.h>
#include <windows.h>
#include <io.h>
#include <cstdio>
#include <unordered_map>
#include <algorithm>
#include "serial.h"
/* See amd-dbgapi-hdep.h. */
const amd_dbgapi_notifier_t null_amd_dbgapi_notifier = nullptr;
/* Use a custom implementation of serial for events from dbgapi. This is
really similar to what is implemented in ser-event.c, except that here:
- The underlying event object is not managed by us, but by dbgapi
instead.
- We keep a handy mapping from event object handles to serial
events for lookup.
*/
struct amd_dbgapi_serial_event_state
{
/* The Windows event handle, provided by dbgapi. */
HANDLE event;
};
/* Mapping from event object handles to serial events for lookup. */
static std::unordered_map<HANDLE, serial *> serial_event_cache;
/* serial_ops::open implementation for the amd-dbgapi serial
event. */
static void
amd_dbgapi_serial_event_state_open (struct serial *scb,
const char *name)
{
auto *state = new amd_dbgapi_serial_event_state;
scb->state = state;
HANDLE dummy_file = CreateFile ("nul", 0, 0, nullptr, OPEN_EXISTING, 0,
nullptr);
scb->fd = _open_osfhandle ((intptr_t) dummy_file, 0);
};
/* serial_ops::close implementation for the amd-dbgapi serial
event. */
static void
amd_dbgapi_serial_event_state_close (struct serial *scb)
{
scb->fd = -1;
delete (amd_dbgapi_serial_event_state *) scb->state;
scb->state = nullptr;
}
/* serial_ops::wait_handle implementation for the amd-dbgapi serial
event. */
static void
amd_dbgapi_serial_event_state_wait_handle (struct serial *scb,
HANDLE *read,
HANDLE *except)
{
auto *state = (amd_dbgapi_serial_event_state *) scb->state;
*read = state->event;
}
static const struct serial_ops amd_dbgapi_serial_event_ops =
{
"amd-dbgapi-event",
amd_dbgapi_serial_event_state_open,
amd_dbgapi_serial_event_state_close,
nullptr, /* fdopen */
nullptr, /* readchar */
nullptr, /* write */
nullptr, /* flush_output */
nullptr, /* flush_input */
nullptr, /* send_break */
nullptr, /* go_raw */
nullptr, /* get_tty_state */
nullptr, /* copy_tty_state */
nullptr, /* set_tty_state */
nullptr, /* print_tty_state */
nullptr, /* setbaudrate */
nullptr, /* setstopbits */
nullptr, /* setparity */
nullptr, /* drain_output */
nullptr, /* async */
nullptr, /* read_prim */
nullptr, /* write_prim */
nullptr, /* avail */
amd_dbgapi_serial_event_state_wait_handle,
nullptr, /* done_wait_handle */
};
/* Return the serial object associated with EVENT_HANDLE, creating it
if necessary. */
static serial *
get_serial_event (HANDLE event_handle)
{
auto it = serial_event_cache.find (event_handle);
/* If we already have a FD for this event, return it. */
if (it != serial_event_cache.end ())
return it->second;
serial *scb = serial_open_ops (&amd_dbgapi_serial_event_ops);
/* Set the underlying Windows event object. */
auto *state = (amd_dbgapi_serial_event_state *) scb->state;
state->event = event_handle;
serial_event_cache.insert ({event_handle, scb});
/* Keep one reference for the cache. This will be released by
amd_dbgapi_notifier_release. */
serial_ref (scb);
return scb;
}
/* See amd-dbgapi-hdep.h. */
void
amd_dbgapi_notifier_clear (amd_dbgapi_notifier_t notifier)
{
ResetEvent (notifier);
}
/* See amd-dbgapi-hdep.h. */
int
amd_dbgapi_notifier_get_fd (amd_dbgapi_notifier_t notifier)
{
return get_serial_event (notifier)->fd;
}
/* See amd-dbgapi-hdep.h. */
void
amd_dbgapi_notifier_release (amd_dbgapi_notifier_t notifier)
{
/* Remove the serial from the cache. */
auto it = serial_event_cache.find (notifier);
if (it != serial_event_cache.end ())
{
serial_event_cache.erase (it);
serial_unref (get_serial_event (notifier));
}
}