Remove indirection from tui_data_window::regs_content
[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   num_ready = 0;
68   num_handles = 0;
69   num_scbs = 0;
70   for (fd = 0; fd < n; ++fd)
71     {
72       HANDLE read = NULL, except = NULL;
73       struct serial *scb;
74
75       /* There is no support yet for WRITEFDS.  At present, this isn't
76          used by GDB -- but we do not want to silently ignore WRITEFDS
77          if something starts using it.  */
78       gdb_assert (!writefds || !FD_ISSET (fd, writefds));
79
80       if ((!readfds || !FD_ISSET (fd, readfds))
81           && (!exceptfds || !FD_ISSET (fd, exceptfds)))
82         continue;
83
84       scb = serial_for_fd (fd);
85       if (scb)
86         {
87           serial_wait_handle (scb, &read, &except);
88           scbs[num_scbs++] = scb;
89         }
90
91       if (read == NULL)
92         read = (HANDLE) _get_osfhandle (fd);
93       if (except == NULL)
94         {
95           if (!never_handle)
96             never_handle = CreateEvent (0, FALSE, FALSE, 0);
97
98           except = never_handle;
99         }
100
101       if (readfds && FD_ISSET (fd, readfds))
102         {
103           gdb_assert (num_handles < MAXIMUM_WAIT_OBJECTS);
104           handles[num_handles++] = read;
105         }
106
107       if (exceptfds && FD_ISSET (fd, exceptfds))
108         {
109           gdb_assert (num_handles < MAXIMUM_WAIT_OBJECTS);
110           handles[num_handles++] = except;
111         }
112     }
113
114   gdb_assert (num_handles <= MAXIMUM_WAIT_OBJECTS);
115
116   event = WaitForMultipleObjects (num_handles,
117                                   handles,
118                                   FALSE,
119                                   timeout
120                                   ? (timeout->tv_sec * 1000
121                                      + timeout->tv_usec / 1000)
122                                   : INFINITE);
123   /* EVENT can only be a value in the WAIT_ABANDONED_0 range if the
124      HANDLES included an abandoned mutex.  Since GDB doesn't use
125      mutexes, that should never occur.  */
126   gdb_assert (!(WAIT_ABANDONED_0 <= event
127                 && event < WAIT_ABANDONED_0 + num_handles));
128   /* We no longer need the helper threads to check for activity.  */
129   for (indx = 0; indx < num_scbs; ++indx)
130     serial_done_wait_handle (scbs[indx]);
131   if (event == WAIT_FAILED)
132     return -1;
133   if (event == WAIT_TIMEOUT)
134     return 0;
135   /* Run through the READFDS, clearing bits corresponding to descriptors
136      for which input is unavailable.  */
137   h = handles[event - WAIT_OBJECT_0];
138   for (fd = 0, indx = 0; fd < n; ++fd)
139     {
140       HANDLE fd_h;
141
142       if ((!readfds || !FD_ISSET (fd, readfds))
143           && (!exceptfds || !FD_ISSET (fd, exceptfds)))
144         continue;
145
146       if (readfds && FD_ISSET (fd, readfds))
147         {
148           fd_h = handles[indx++];
149           /* This handle might be ready, even though it wasn't the handle
150              returned by WaitForMultipleObjects.  */
151           if (fd_h != h && WaitForSingleObject (fd_h, 0) != WAIT_OBJECT_0)
152             FD_CLR (fd, readfds);
153           else
154             num_ready++;
155         }
156
157       if (exceptfds && FD_ISSET (fd, exceptfds))
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, exceptfds);
164           else
165             num_ready++;
166         }
167     }
168
169   return num_ready;
170 }
171
172 /* Map COLOR's RGB triplet, with 8 bits per component, into 16 Windows
173    console colors, where each component has just 1 bit, plus a single
174    intensity bit which affects all 3 components.  */
175 static int
176 rgb_to_16colors (const ui_file_style::color &color)
177 {
178   uint8_t rgb[3];
179   color.get_rgb (rgb);
180
181   int retval = 0;
182   for (int i = 0; i < 3; i++)
183     {
184       /* Subdivide 256 possible values of each RGB component into 3
185          regions: no color, normal color, bright color.  256 / 3 = 85,
186          but ui-style.c follows xterm and uses 92 for R and G
187          components of the bright-blue color, so we bias the divisor a
188          bit to have the bright colors between 9 and 15 identical to
189          what ui-style.c expects.  */
190       int bits = rgb[i] / 93;
191       retval |= ((bits > 0) << (2 - i)) | ((bits > 1) << 3);
192     }
193
194   return retval;
195 }
196
197 /* Zero if not yet initialized, 1 if stdout is a console device, else -1.  */
198 static int mingw_console_initialized;
199
200 /* Handle to stdout . */
201 static HANDLE hstdout = INVALID_HANDLE_VALUE;
202
203 /* Text attribute to use for normal text (the "none" pseudo-color).  */
204 static SHORT  norm_attr;
205
206 /* The most recently applied style.  */
207 static ui_file_style last_style;
208
209 /* Alternative for the libc 'fputs' which handles embedded SGR
210    sequences in support of styling.  */
211
212 int
213 gdb_console_fputs (const char *linebuf, FILE *fstream)
214 {
215   if (!mingw_console_initialized)
216     {
217       hstdout = (HANDLE)_get_osfhandle (fileno (fstream));
218       DWORD cmode;
219       CONSOLE_SCREEN_BUFFER_INFO csbi;
220
221       if (hstdout != INVALID_HANDLE_VALUE
222           && GetConsoleMode (hstdout, &cmode) != 0
223           && GetConsoleScreenBufferInfo (hstdout, &csbi))
224         {
225           norm_attr = csbi.wAttributes;
226           mingw_console_initialized = 1;
227         }
228       else if (hstdout != INVALID_HANDLE_VALUE)
229         mingw_console_initialized = -1; /* valid, but not a console device */
230     }
231   /* If our stdout is not a console device, let the default 'fputs'
232      handle the task. */
233   if (mingw_console_initialized <= 0)
234     return 0;
235
236   /* Mapping between 8 ANSI colors and Windows console attributes.  */
237   static int fg_color[] = {
238     0,                                  /* black */
239     FOREGROUND_RED,                     /* red */
240     FOREGROUND_GREEN,                   /* green */
241     FOREGROUND_GREEN | FOREGROUND_RED,  /* yellow */
242     FOREGROUND_BLUE,                    /* blue */
243     FOREGROUND_BLUE | FOREGROUND_RED,   /* magenta */
244     FOREGROUND_BLUE | FOREGROUND_GREEN, /* cyan */
245     FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE /* gray */
246   };
247   static int bg_color[] = {
248     0,                                  /* black */
249     BACKGROUND_RED,                     /* red */
250     BACKGROUND_GREEN,                   /* green */
251     BACKGROUND_GREEN | BACKGROUND_RED,  /* yellow */
252     BACKGROUND_BLUE,                    /* blue */
253     BACKGROUND_BLUE | BACKGROUND_RED,   /* magenta */
254     BACKGROUND_BLUE | BACKGROUND_GREEN, /* cyan */
255     BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE /* gray */
256   };
257
258   ui_file_style style = last_style;
259   unsigned char c;
260   size_t n_read;
261
262   for ( ; (c = *linebuf) != 0; linebuf += n_read)
263     {
264       if (c == '\033')
265         {
266           fflush (fstream);
267           bool parsed = style.parse (linebuf, &n_read);
268           if (n_read <= 0)      /* should never happen */
269             n_read = 1;
270           if (!parsed)
271             {
272               /* This means we silently swallow SGR sequences we
273                  cannot parse.  */
274               continue;
275             }
276           /* Colors.  */
277           const ui_file_style::color &fg = style.get_foreground ();
278           const ui_file_style::color &bg = style.get_background ();
279           int fgcolor, bgcolor, bright, inverse;
280           if (fg.is_none ())
281             fgcolor = norm_attr & 15;
282           else if (fg.is_basic ())
283             fgcolor = fg_color[fg.get_value () & 15];
284           else
285             fgcolor = rgb_to_16colors (fg);
286           if (bg.is_none ())
287             bgcolor = norm_attr & (15 << 4);
288           else if (bg.is_basic ())
289             bgcolor = bg_color[bg.get_value () & 15];
290           else
291             bgcolor = rgb_to_16colors (bg) << 4;
292
293           /* Intensity.  */
294           switch (style.get_intensity ())
295             {
296             case ui_file_style::NORMAL:
297             case ui_file_style::DIM:
298               bright = 0;
299               break;
300             case ui_file_style::BOLD:
301               bright = 1;
302               break;
303             default:
304               gdb_assert_not_reached ("invalid intensity");
305             }
306
307           /* Inverse video.  */
308           if (style.is_reverse ())
309             inverse = 1;
310           else
311             inverse = 0;
312
313           /* Construct the attribute.  */
314           if (inverse)
315             {
316               int t = fgcolor;
317               fgcolor = (bgcolor >> 4);
318               bgcolor = (t << 4);
319             }
320           if (bright)
321             fgcolor |= FOREGROUND_INTENSITY;
322
323           SHORT attr = (bgcolor & (15 << 4)) | (fgcolor & 15);
324
325           /* Apply the attribute.  */
326           SetConsoleTextAttribute (hstdout, attr);
327         }
328       else
329         {
330           /* When we are about to write newline, we need to clear to
331              EOL with the normal attribute, to avoid spilling the
332              colors to the next screen line.  We assume here that no
333              non-default attribute extends beyond the newline.  */
334           if (c == '\n')
335             {
336               DWORD nchars;
337               COORD start_pos;
338               DWORD written;
339               CONSOLE_SCREEN_BUFFER_INFO csbi;
340
341               fflush (fstream);
342               GetConsoleScreenBufferInfo (hstdout, &csbi);
343
344               if (csbi.wAttributes != norm_attr)
345                 {
346                   start_pos = csbi.dwCursorPosition;
347                   nchars = csbi.dwSize.X - start_pos.X;
348
349                   FillConsoleOutputAttribute (hstdout, norm_attr, nchars,
350                                               start_pos, &written);
351                   FillConsoleOutputCharacter (hstdout, ' ', nchars,
352                                               start_pos, &written);
353                 }
354             }
355           fputc (c, fstream);
356           n_read = 1;
357         }
358     }
359
360   last_style = style;
361   return 1;
362 }