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