]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - gdb/mingw-hdep.c
Automatic date update in version.in
[thirdparty/binutils-gdb.git] / gdb / mingw-hdep.c
CommitLineData
121ce6e5
DJ
1/* Host support routines for MinGW, for GDB, the GNU debugger.
2
1d506c26 3 Copyright (C) 2006-2024 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 19
d9ac0664 20#include "main.h"
0ea3f30e 21#include "serial.h"
400b5eca 22#include "gdbsupport/event-loop.h"
06cc9596 23#include "gdbsupport/gdb_select.h"
c1dc47f5 24#include "inferior.h"
121ce6e5
DJ
25
26#include <windows.h>
c88afe9c 27#include <signal.h>
121ce6e5 28
d9ac0664
EZ
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
32char *
33windows_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
0ea3f30e
DJ
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
49int
50gdb_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;
4577549b
DJ
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;
0ea3f30e
DJ
63 int fd;
64 int num_ready;
4577549b 65 size_t indx;
0ea3f30e 66
16d01f9c
BW
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
0ea3f30e
DJ
78 num_ready = 0;
79 num_handles = 0;
4577549b 80 num_scbs = 0;
0ea3f30e
DJ
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
98739726
DJ
91 if ((!readfds || !FD_ISSET (fd, readfds))
92 && (!exceptfds || !FD_ISSET (fd, exceptfds)))
0ea3f30e 93 continue;
0ea3f30e
DJ
94
95 scb = serial_for_fd (fd);
96 if (scb)
4577549b
DJ
97 {
98 serial_wait_handle (scb, &read, &except);
99 scbs[num_scbs++] = scb;
100 }
0ea3f30e
DJ
101
102 if (read == NULL)
4577549b 103 read = (HANDLE) _get_osfhandle (fd);
0ea3f30e
DJ
104 if (except == NULL)
105 {
106 if (!never_handle)
107 never_handle = CreateEvent (0, FALSE, FALSE, 0);
108
109 except = never_handle;
110 }
111
98739726 112 if (readfds && FD_ISSET (fd, readfds))
0ea3f30e
DJ
113 {
114 gdb_assert (num_handles < MAXIMUM_WAIT_OBJECTS);
115 handles[num_handles++] = read;
116 }
117
98739726 118 if (exceptfds && FD_ISSET (fd, exceptfds))
0ea3f30e
DJ
119 {
120 gdb_assert (num_handles < MAXIMUM_WAIT_OBJECTS);
121 handles[num_handles++] = except;
122 }
123 }
0ea3f30e 124
585a46a2 125 gdb_assert (num_handles <= MAXIMUM_WAIT_OBJECTS);
0ea3f30e
DJ
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));
4577549b
DJ
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]);
0ea3f30e
DJ
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;
c3e2b812 152
98739726
DJ
153 if ((!readfds || !FD_ISSET (fd, readfds))
154 && (!exceptfds || !FD_ISSET (fd, exceptfds)))
c3e2b812 155 continue;
0ea3f30e 156
98739726 157 if (readfds && FD_ISSET (fd, readfds))
0ea3f30e
DJ
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
98739726 168 if (exceptfds && FD_ISSET (fd, exceptfds))
0ea3f30e
DJ
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}
e4adb939
EZ
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. */
186static int
187rgb_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. */
209static int mingw_console_initialized;
210
211/* Handle to stdout . */
212static HANDLE hstdout = INVALID_HANDLE_VALUE;
213
214/* Text attribute to use for normal text (the "none" pseudo-color). */
215static SHORT norm_attr;
216
217/* The most recently applied style. */
218static ui_file_style last_style;
219
220/* Alternative for the libc 'fputs' which handles embedded SGR
221 sequences in support of styling. */
222
223int
224gdb_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}
c1dc47f5
TT
374
375/* See inferior.h. */
376
377tribool
378sharing_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". */
2c9d7827 387 if (len <= results.size ())
c1dc47f5
TT
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}
c88afe9c
TT
403
404/* Current C-c handler. */
405static c_c_handler_ftype *current_handler;
406
407/* The Windows callback that forwards requests to the C-c handler. */
408static BOOL WINAPI
409ctrl_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
423c_c_handler_ftype *
424install_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}