1 /* Host support routines for MinGW, for GDB, the GNU debugger.
3 Copyright (C) 2006-2024 Free Software Foundation, Inc.
5 This file is part of GDB.
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.
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.
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/>. */
23 #include "gdbsupport/event-loop.h"
24 #include "gdbsupport/gdb_select.h"
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. */
34 windows_get_absolute_argv0 (const char *argv0
)
36 char full_name
[PATH_MAX
];
38 if (GetModuleFileName (NULL
, full_name
, PATH_MAX
))
39 return xstrdup (full_name
);
40 return xstrdup (argv0
);
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.
47 The arguments to this function are the same as the traditional
48 arguments to select on POSIX platforms. */
51 gdb_select (int n
, fd_set
*readfds
, fd_set
*writefds
, fd_set
*exceptfds
,
52 struct timeval
*timeout
)
54 static HANDLE never_handle
;
55 HANDLE handles
[MAXIMUM_WAIT_OBJECTS
];
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. */
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. */
74 Sleep (timeout
->tv_sec
* 1000 + timeout
->tv_usec
/ 1000);
82 for (fd
= 0; fd
< n
; ++fd
)
84 HANDLE read
= NULL
, except
= NULL
;
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
));
92 if ((!readfds
|| !FD_ISSET (fd
, readfds
))
93 && (!exceptfds
|| !FD_ISSET (fd
, exceptfds
)))
96 scb
= serial_for_fd (fd
);
99 serial_wait_handle (scb
, &read
, &except
);
100 scbs
[num_scbs
++] = scb
;
104 read
= (HANDLE
) _get_osfhandle (fd
);
108 never_handle
= CreateEvent (0, FALSE
, FALSE
, 0);
110 except
= never_handle
;
113 if (readfds
&& FD_ISSET (fd
, readfds
))
115 gdb_assert (num_handles
< MAXIMUM_WAIT_OBJECTS
);
116 handles
[num_handles
++] = read
;
119 if (exceptfds
&& FD_ISSET (fd
, exceptfds
))
121 gdb_assert (num_handles
< MAXIMUM_WAIT_OBJECTS
);
122 handles
[num_handles
++] = except
;
126 gdb_assert (num_handles
<= MAXIMUM_WAIT_OBJECTS
);
128 event
= WaitForMultipleObjects (num_handles
,
132 ? (timeout
->tv_sec
* 1000
133 + timeout
->tv_usec
/ 1000)
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
));
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
]);
143 if (event
== WAIT_FAILED
)
145 if (event
== WAIT_TIMEOUT
)
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
)
154 if ((!readfds
|| !FD_ISSET (fd
, readfds
))
155 && (!exceptfds
|| !FD_ISSET (fd
, exceptfds
)))
158 if (readfds
&& FD_ISSET (fd
, readfds
))
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
);
169 if (exceptfds
&& FD_ISSET (fd
, exceptfds
))
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
);
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. */
188 rgb_to_16colors (const ui_file_style::color
&color
)
194 for (int i
= 0; i
< 3; i
++)
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);
209 /* Zero if not yet initialized, 1 if stdout is a console device, else -1. */
210 static int mingw_console_initialized
;
212 /* Handle to stdout . */
213 static HANDLE hstdout
= INVALID_HANDLE_VALUE
;
215 /* Text attribute to use for normal text (the "none" pseudo-color). */
216 static SHORT norm_attr
;
218 /* The most recently applied style. */
219 static ui_file_style last_style
;
221 /* Alternative for the libc 'fputs' which handles embedded SGR
222 sequences in support of styling. */
225 gdb_console_fputs (const char *linebuf
, FILE *fstream
)
227 if (!mingw_console_initialized
)
229 hstdout
= (HANDLE
)_get_osfhandle (fileno (fstream
));
231 CONSOLE_SCREEN_BUFFER_INFO csbi
;
233 if (hstdout
!= INVALID_HANDLE_VALUE
234 && GetConsoleMode (hstdout
, &cmode
) != 0
235 && GetConsoleScreenBufferInfo (hstdout
, &csbi
))
237 norm_attr
= csbi
.wAttributes
;
238 mingw_console_initialized
= 1;
240 else if (hstdout
!= INVALID_HANDLE_VALUE
)
241 mingw_console_initialized
= -1; /* valid, but not a console device */
243 /* If our stdout is not a console device, let the default 'fputs'
245 if (mingw_console_initialized
<= 0)
248 /* Mapping between 8 ANSI colors and Windows console attributes. */
249 static int fg_color
[] = {
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 */
259 static int bg_color
[] = {
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 */
270 ui_file_style style
= last_style
;
274 for ( ; (c
= *linebuf
) != 0; linebuf
+= n_read
)
279 bool parsed
= style
.parse (linebuf
, &n_read
);
280 if (n_read
<= 0) /* should never happen */
284 /* This means we silently swallow SGR sequences we
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
;
293 fgcolor
= norm_attr
& 15;
294 else if (fg
.is_basic ())
295 fgcolor
= fg_color
[fg
.get_value () & 15];
297 fgcolor
= rgb_to_16colors (fg
);
299 bgcolor
= norm_attr
& (15 << 4);
300 else if (bg
.is_basic ())
301 bgcolor
= bg_color
[bg
.get_value () & 15];
303 bgcolor
= rgb_to_16colors (bg
) << 4;
306 switch (style
.get_intensity ())
308 case ui_file_style::NORMAL
:
309 case ui_file_style::DIM
:
312 case ui_file_style::BOLD
:
316 gdb_assert_not_reached ("invalid intensity");
320 if (style
.is_reverse ())
325 /* Construct the attribute. */
329 fgcolor
= (bgcolor
>> 4);
333 fgcolor
|= FOREGROUND_INTENSITY
;
335 SHORT attr
= (bgcolor
& (15 << 4)) | (fgcolor
& 15);
337 /* Apply the attribute. */
338 SetConsoleTextAttribute (hstdout
, attr
);
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. */
351 CONSOLE_SCREEN_BUFFER_INFO csbi
;
354 GetConsoleScreenBufferInfo (hstdout
, &csbi
);
356 if (csbi
.wAttributes
!= norm_attr
)
358 start_pos
= csbi
.dwCursorPosition
;
359 nchars
= csbi
.dwSize
.X
- start_pos
.X
;
361 FillConsoleOutputAttribute (hstdout
, norm_attr
, nchars
,
362 start_pos
, &written
);
363 FillConsoleOutputCharacter (hstdout
, ' ', nchars
,
364 start_pos
, &written
);
376 /* See inferior.h. */
379 sharing_input_terminal (int pid
)
381 std::vector
<DWORD
> results (10);
385 len
= GetConsoleProcessList (results
.data (), results
.size ());
386 /* Note that LEN == 0 is a failure, but we can treat it the same
388 if (len
<= results
.size ())
391 results
.resize (len
);
393 /* In case the vector was too big. */
394 results
.resize (len
);
395 if (std::find (results
.begin (), results
.end (), pid
) != results
.end ())
397 /* The pid is in the list sharing the console, so don't
398 interrupt the inferior -- it will get the signal itself. */
402 return TRIBOOL_FALSE
;
405 /* Current C-c handler. */
406 static c_c_handler_ftype
*current_handler
;
408 /* The Windows callback that forwards requests to the C-c handler. */
410 ctrl_c_handler (DWORD event_type
)
412 if (event_type
== CTRL_BREAK_EVENT
|| event_type
== CTRL_C_EVENT
)
414 if (current_handler
!= SIG_IGN
)
415 current_handler (SIGINT
);
422 /* See inferior.h. */
425 install_sigint_handler (c_c_handler_ftype
*fn
)
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;
433 SetConsoleCtrlHandler (ctrl_c_handler
, FALSE
);
434 SetConsoleCtrlHandler (ctrl_c_handler
, TRUE
);
437 c_c_handler_ftype
*result
= current_handler
;
438 current_handler
= fn
;