0af1b39acdcc9987a73669f9116d05474d843fc9
[external/binutils.git] / gdb / mingw-hdep.c
1 /* Host support routines for MinGW, for GDB, the GNU debugger.
2
3    Copyright (C) 2006-2019 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 "event-loop.h"
24
25 #include "gdb_select.h"
26
27 #include <windows.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 *
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
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
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
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 }