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