1/* Host support routines for MinGW, for GDB, the GNU debugger.
2
3   Copyright (C) 2006-2023 Free Software Foundation, Inc.
4
5   This file is part of GDB.
6
7   This program is free software; you can redistribute it and/or modify
8   it under the terms of the GNU General Public License as published by
9   the Free Software Foundation; either version 3 of the License, or
10   (at your option) any later version.
11
12   This program is distributed in the hope that it will be useful,
13   but WITHOUT ANY WARRANTY; without even the implied warranty of
14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15   GNU General Public License for more details.
16
17   You should have received a copy of the GNU General Public License
18   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
19
20#include "defs.h"
21#include "main.h"
22#include "serial.h"
23#include "gdbsupport/event-loop.h"
24#include "gdbsupport/gdb_select.h"
25#include "inferior.h"
26
27#include <windows.h>
28#include <signal.h>
29
30/* Return an absolute file name of the running GDB, if possible, or
31   ARGV0 if not.  The return value is in malloc'ed storage.  */
32
33char *
34windows_get_absolute_argv0 (const char *argv0)
35{
36  char full_name[PATH_MAX];
37
38  if (GetModuleFileName (NULL, full_name, PATH_MAX))
39    return xstrdup (full_name);
40  return xstrdup (argv0);
41}
42
43/* Wrapper for select.  On Windows systems, where the select interface
44   only works for sockets, this uses the GDB serial abstraction to
45   handle sockets, consoles, pipes, and serial ports.
46
47   The arguments to this function are the same as the traditional
48   arguments to select on POSIX platforms.  */
49
50int
51gdb_select (int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
52	    struct timeval *timeout)
53{
54  static HANDLE never_handle;
55  HANDLE handles[MAXIMUM_WAIT_OBJECTS];
56  HANDLE h;
57  DWORD event;
58  DWORD num_handles;
59  /* SCBS contains serial control objects corresponding to file
60     descriptors in READFDS and WRITEFDS.  */
61  struct serial *scbs[MAXIMUM_WAIT_OBJECTS];
62  /* The number of valid entries in SCBS.  */
63  size_t num_scbs;
64  int fd;
65  int num_ready;
66  size_t indx;
67
68  if (n == 0)
69    {
70      /* The MS API says that the first argument to
71	 WaitForMultipleObjects cannot be zero.  That's why we just
72	 use a regular Sleep here.  */
73      if (timeout != NULL)
74	Sleep (timeout->tv_sec * 1000 + timeout->tv_usec / 1000);
75
76      return 0;
77    }
78
79  num_ready = 0;
80  num_handles = 0;
81  num_scbs = 0;
82  for (fd = 0; fd < n; ++fd)
83    {
84      HANDLE read = NULL, except = NULL;
85      struct serial *scb;
86
87      /* There is no support yet for WRITEFDS.  At present, this isn't
88	 used by GDB -- but we do not want to silently ignore WRITEFDS
89	 if something starts using it.  */
90      gdb_assert (!writefds || !FD_ISSET (fd, writefds));
91
92      if ((!readfds || !FD_ISSET (fd, readfds))
93	  && (!exceptfds || !FD_ISSET (fd, exceptfds)))
94	continue;
95
96      scb = serial_for_fd (fd);
97      if (scb)
98	{
99	  serial_wait_handle (scb, &read, &except);
100	  scbs[num_scbs++] = scb;
101	}
102
103      if (read == NULL)
104	read = (HANDLE) _get_osfhandle (fd);
105      if (except == NULL)
106	{
107	  if (!never_handle)
108	    never_handle = CreateEvent (0, FALSE, FALSE, 0);
109
110	  except = never_handle;
111	}
112
113      if (readfds && FD_ISSET (fd, readfds))
114	{
115	  gdb_assert (num_handles < MAXIMUM_WAIT_OBJECTS);
116	  handles[num_handles++] = read;
117	}
118
119      if (exceptfds && FD_ISSET (fd, exceptfds))
120	{
121	  gdb_assert (num_handles < MAXIMUM_WAIT_OBJECTS);
122	  handles[num_handles++] = except;
123	}
124    }
125
126  gdb_assert (num_handles <= MAXIMUM_WAIT_OBJECTS);
127
128  event = WaitForMultipleObjects (num_handles,
129				  handles,
130				  FALSE,
131				  timeout
132				  ? (timeout->tv_sec * 1000
133				     + timeout->tv_usec / 1000)
134				  : INFINITE);
135  /* EVENT can only be a value in the WAIT_ABANDONED_0 range if the
136     HANDLES included an abandoned mutex.  Since GDB doesn't use
137     mutexes, that should never occur.  */
138  gdb_assert (!(WAIT_ABANDONED_0 <= event
139		&& event < WAIT_ABANDONED_0 + num_handles));
140  /* We no longer need the helper threads to check for activity.  */
141  for (indx = 0; indx < num_scbs; ++indx)
142    serial_done_wait_handle (scbs[indx]);
143  if (event == WAIT_FAILED)
144    return -1;
145  if (event == WAIT_TIMEOUT)
146    return 0;
147  /* Run through the READFDS, clearing bits corresponding to descriptors
148     for which input is unavailable.  */
149  h = handles[event - WAIT_OBJECT_0];
150  for (fd = 0, indx = 0; fd < n; ++fd)
151    {
152      HANDLE fd_h;
153
154      if ((!readfds || !FD_ISSET (fd, readfds))
155	  && (!exceptfds || !FD_ISSET (fd, exceptfds)))
156	continue;
157
158      if (readfds && FD_ISSET (fd, readfds))
159	{
160	  fd_h = handles[indx++];
161	  /* This handle might be ready, even though it wasn't the handle
162	     returned by WaitForMultipleObjects.  */
163	  if (fd_h != h && WaitForSingleObject (fd_h, 0) != WAIT_OBJECT_0)
164	    FD_CLR (fd, readfds);
165	  else
166	    num_ready++;
167	}
168
169      if (exceptfds && FD_ISSET (fd, exceptfds))
170	{
171	  fd_h = handles[indx++];
172	  /* This handle might be ready, even though it wasn't the handle
173	     returned by WaitForMultipleObjects.  */
174	  if (fd_h != h && WaitForSingleObject (fd_h, 0) != WAIT_OBJECT_0)
175	    FD_CLR (fd, exceptfds);
176	  else
177	    num_ready++;
178	}
179    }
180
181  return num_ready;
182}
183
184/* Map COLOR's RGB triplet, with 8 bits per component, into 16 Windows
185   console colors, where each component has just 1 bit, plus a single
186   intensity bit which affects all 3 components.  */
187static int
188rgb_to_16colors (const ui_file_style::color &color)
189{
190  uint8_t rgb[3];
191  color.get_rgb (rgb);
192
193  int retval = 0;
194  for (int i = 0; i < 3; i++)
195    {
196      /* Subdivide 256 possible values of each RGB component into 3
197	 regions: no color, normal color, bright color.  256 / 3 = 85,
198	 but ui-style.c follows xterm and uses 92 for R and G
199	 components of the bright-blue color, so we bias the divisor a
200	 bit to have the bright colors between 9 and 15 identical to
201	 what ui-style.c expects.  */
202      int bits = rgb[i] / 93;
203      retval |= ((bits > 0) << (2 - i)) | ((bits > 1) << 3);
204    }
205
206  return retval;
207}
208
209/* Zero if not yet initialized, 1 if stdout is a console device, else -1.  */
210static int mingw_console_initialized;
211
212/* Handle to stdout . */
213static HANDLE hstdout = INVALID_HANDLE_VALUE;
214
215/* Text attribute to use for normal text (the "none" pseudo-color).  */
216static SHORT  norm_attr;
217
218/* The most recently applied style.  */
219static ui_file_style last_style;
220
221/* Alternative for the libc 'fputs' which handles embedded SGR
222   sequences in support of styling.  */
223
224int
225gdb_console_fputs (const char *linebuf, FILE *fstream)
226{
227  if (!mingw_console_initialized)
228    {
229      hstdout = (HANDLE)_get_osfhandle (fileno (fstream));
230      DWORD cmode;
231      CONSOLE_SCREEN_BUFFER_INFO csbi;
232
233      if (hstdout != INVALID_HANDLE_VALUE
234	  && GetConsoleMode (hstdout, &cmode) != 0
235	  && GetConsoleScreenBufferInfo (hstdout, &csbi))
236	{
237	  norm_attr = csbi.wAttributes;
238	  mingw_console_initialized = 1;
239	}
240      else if (hstdout != INVALID_HANDLE_VALUE)
241	mingw_console_initialized = -1; /* valid, but not a console device */
242    }
243  /* If our stdout is not a console device, let the default 'fputs'
244     handle the task. */
245  if (mingw_console_initialized <= 0)
246    return 0;
247
248  /* Mapping between 8 ANSI colors and Windows console attributes.  */
249  static int fg_color[] = {
250    0,					/* black */
251    FOREGROUND_RED,			/* red */
252    FOREGROUND_GREEN,			/* green */
253    FOREGROUND_GREEN | FOREGROUND_RED,	/* yellow */
254    FOREGROUND_BLUE,			/* blue */
255    FOREGROUND_BLUE | FOREGROUND_RED,	/* magenta */
256    FOREGROUND_BLUE | FOREGROUND_GREEN, /* cyan */
257    FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE /* gray */
258  };
259  static int bg_color[] = {
260    0,					/* black */
261    BACKGROUND_RED,			/* red */
262    BACKGROUND_GREEN,			/* green */
263    BACKGROUND_GREEN | BACKGROUND_RED,	/* yellow */
264    BACKGROUND_BLUE,			/* blue */
265    BACKGROUND_BLUE | BACKGROUND_RED,	/* magenta */
266    BACKGROUND_BLUE | BACKGROUND_GREEN, /* cyan */
267    BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE /* gray */
268  };
269
270  ui_file_style style = last_style;
271  unsigned char c;
272  size_t n_read;
273
274  for ( ; (c = *linebuf) != 0; linebuf += n_read)
275    {
276      if (c == '\033')
277	{
278	  fflush (fstream);
279	  bool parsed = style.parse (linebuf, &n_read);
280	  if (n_read <= 0)	/* should never happen */
281	    n_read = 1;
282	  if (!parsed)
283	    {
284	      /* This means we silently swallow SGR sequences we
285		 cannot parse.  */
286	      continue;
287	    }
288	  /* Colors.  */
289	  const ui_file_style::color &fg = style.get_foreground ();
290	  const ui_file_style::color &bg = style.get_background ();
291	  int fgcolor, bgcolor, bright, inverse;
292	  if (fg.is_none ())
293	    fgcolor = norm_attr & 15;
294	  else if (fg.is_basic ())
295	    fgcolor = fg_color[fg.get_value () & 15];
296	  else
297	    fgcolor = rgb_to_16colors (fg);
298	  if (bg.is_none ())
299	    bgcolor = norm_attr & (15 << 4);
300	  else if (bg.is_basic ())
301	    bgcolor = bg_color[bg.get_value () & 15];
302	  else
303	    bgcolor = rgb_to_16colors (bg) << 4;
304
305	  /* Intensity.  */
306	  switch (style.get_intensity ())
307	    {
308	    case ui_file_style::NORMAL:
309	    case ui_file_style::DIM:
310	      bright = 0;
311	      break;
312	    case ui_file_style::BOLD:
313	      bright = 1;
314	      break;
315	    default:
316	      gdb_assert_not_reached ("invalid intensity");
317	    }
318
319	  /* Inverse video.  */
320	  if (style.is_reverse ())
321	    inverse = 1;
322	  else
323	    inverse = 0;
324
325	  /* Construct the attribute.  */
326	  if (inverse)
327	    {
328	      int t = fgcolor;
329	      fgcolor = (bgcolor >> 4);
330	      bgcolor = (t << 4);
331	    }
332	  if (bright)
333	    fgcolor |= FOREGROUND_INTENSITY;
334
335	  SHORT attr = (bgcolor & (15 << 4)) | (fgcolor & 15);
336
337	  /* Apply the attribute.  */
338	  SetConsoleTextAttribute (hstdout, attr);
339	}
340      else
341	{
342	  /* When we are about to write newline, we need to clear to
343	     EOL with the normal attribute, to avoid spilling the
344	     colors to the next screen line.  We assume here that no
345	     non-default attribute extends beyond the newline.  */
346	  if (c == '\n')
347	    {
348	      DWORD nchars;
349	      COORD start_pos;
350	      DWORD written;
351	      CONSOLE_SCREEN_BUFFER_INFO csbi;
352
353	      fflush (fstream);
354	      GetConsoleScreenBufferInfo (hstdout, &csbi);
355
356	      if (csbi.wAttributes != norm_attr)
357		{
358		  start_pos = csbi.dwCursorPosition;
359		  nchars = csbi.dwSize.X - start_pos.X;
360
361		  FillConsoleOutputAttribute (hstdout, norm_attr, nchars,
362					      start_pos, &written);
363		  FillConsoleOutputCharacter (hstdout, ' ', nchars,
364					      start_pos, &written);
365		}
366	    }
367	  fputc (c, fstream);
368	  n_read = 1;
369	}
370    }
371
372  last_style = style;
373  return 1;
374}
375
376/* See inferior.h.  */
377
378tribool
379sharing_input_terminal (int pid)
380{
381  std::vector<DWORD> results (10);
382  DWORD len = 0;
383  while (true)
384    {
385      len = GetConsoleProcessList (results.data (), results.size ());
386      /* Note that LEN == 0 is a failure, but we can treat it the same
387	 as a "no".  */
388      if (len < results.size ())
389	break;
390
391      results.resize (len);
392    }
393  /* In case the vector was too big.  */
394  results.resize (len);
395  if (std::find (results.begin (), results.end (), pid) != results.end ())
396    {
397      /* The pid is in the list sharing the console, so don't
398	 interrupt the inferior -- it will get the signal itself.  */
399      return TRIBOOL_TRUE;
400    }
401
402  return TRIBOOL_FALSE;
403}
404
405/* Current C-c handler.  */
406static c_c_handler_ftype *current_handler;
407
408/* The Windows callback that forwards requests to the C-c handler.  */
409static BOOL WINAPI
410ctrl_c_handler (DWORD event_type)
411{
412  if (event_type == CTRL_BREAK_EVENT || event_type == CTRL_C_EVENT)
413    {
414      if (current_handler != SIG_IGN)
415	current_handler (SIGINT);
416    }
417  else
418    return FALSE;
419  return TRUE;
420}
421
422/* See inferior.h.  */
423
424c_c_handler_ftype *
425install_sigint_handler (c_c_handler_ftype *fn)
426{
427  /* We want to make sure the gdb handler always comes first, so that
428     gdb gets to handle the C-c.  This is why the handler is always
429     removed and reinstalled here.  Note that trying to remove the
430     function without installing it first will cause a crash.  */
431  static bool installed = false;
432  if (installed)
433    SetConsoleCtrlHandler (ctrl_c_handler, FALSE);
434  SetConsoleCtrlHandler (ctrl_c_handler, TRUE);
435  installed = true;
436
437  c_c_handler_ftype *result = current_handler;
438  current_handler = fn;
439  return result;
440}
441