]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - gdb/mingw-hdep.c
Update copyright year range in header of all files managed by GDB
[thirdparty/binutils-gdb.git] / gdb / mingw-hdep.c
CommitLineData
121ce6e5
DJ
1/* Host support routines for MinGW, for GDB, the GNU debugger.
2
213516ef 3 Copyright (C) 2006-2023 Free Software Foundation, Inc.
121ce6e5
DJ
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
a9762ec7 9 the Free Software Foundation; either version 3 of the License, or
121ce6e5
DJ
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
a9762ec7 18 along with this program. If not, see <http://www.gnu.org/licenses/>. */
121ce6e5
DJ
19
20#include "defs.h"
d9ac0664 21#include "main.h"
0ea3f30e 22#include "serial.h"
400b5eca 23#include "gdbsupport/event-loop.h"
06cc9596 24#include "gdbsupport/gdb_select.h"
c1dc47f5 25#include "inferior.h"
121ce6e5
DJ
26
27#include <windows.h>
c88afe9c 28#include <signal.h>
121ce6e5 29
d9ac0664
EZ
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
0ea3f30e
DJ
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;
4577549b
DJ
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;
0ea3f30e
DJ
64 int fd;
65 int num_ready;
4577549b 66 size_t indx;
0ea3f30e 67
16d01f9c
BW
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
0ea3f30e
DJ
79 num_ready = 0;
80 num_handles = 0;
4577549b 81 num_scbs = 0;
0ea3f30e
DJ
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
98739726
DJ
92 if ((!readfds || !FD_ISSET (fd, readfds))
93 && (!exceptfds || !FD_ISSET (fd, exceptfds)))
0ea3f30e 94 continue;
0ea3f30e
DJ
95
96 scb = serial_for_fd (fd);
97 if (scb)
4577549b
DJ
98 {
99 serial_wait_handle (scb, &read, &except);
100 scbs[num_scbs++] = scb;
101 }
0ea3f30e
DJ
102
103 if (read == NULL)
4577549b 104 read = (HANDLE) _get_osfhandle (fd);
0ea3f30e
DJ
105 if (except == NULL)
106 {
107 if (!never_handle)
108 never_handle = CreateEvent (0, FALSE, FALSE, 0);
109
110 except = never_handle;
111 }
112
98739726 113 if (readfds && FD_ISSET (fd, readfds))
0ea3f30e
DJ
114 {
115 gdb_assert (num_handles < MAXIMUM_WAIT_OBJECTS);
116 handles[num_handles++] = read;
117 }
118
98739726 119 if (exceptfds && FD_ISSET (fd, exceptfds))
0ea3f30e
DJ
120 {
121 gdb_assert (num_handles < MAXIMUM_WAIT_OBJECTS);
122 handles[num_handles++] = except;
123 }
124 }
0ea3f30e 125
585a46a2 126 gdb_assert (num_handles <= MAXIMUM_WAIT_OBJECTS);
0ea3f30e
DJ
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));
4577549b
DJ
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]);
0ea3f30e
DJ
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;
c3e2b812 153
98739726
DJ
154 if ((!readfds || !FD_ISSET (fd, readfds))
155 && (!exceptfds || !FD_ISSET (fd, exceptfds)))
c3e2b812 156 continue;
0ea3f30e 157
98739726 158 if (readfds && FD_ISSET (fd, readfds))
0ea3f30e
DJ
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
98739726 169 if (exceptfds && FD_ISSET (fd, exceptfds))
0ea3f30e
DJ
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}
e4adb939
EZ
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}
c1dc47f5
TT
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}
c88afe9c
TT
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}