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/>. */
22 #include "gdbsupport/event-loop.h"
23 #include "gdbsupport/gdb_select.h"
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. */
33 windows_get_absolute_argv0 (const char *argv0
)
35 char full_name
[PATH_MAX
];
37 if (GetModuleFileName (NULL
, full_name
, PATH_MAX
))
38 return xstrdup (full_name
);
39 return xstrdup (argv0
);
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.
46 The arguments to this function are the same as the traditional
47 arguments to select on POSIX platforms. */
50 gdb_select (int n
, fd_set
*readfds
, fd_set
*writefds
, fd_set
*exceptfds
,
51 struct timeval
*timeout
)
53 static HANDLE never_handle
;
54 HANDLE handles
[MAXIMUM_WAIT_OBJECTS
];
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. */
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. */
73 Sleep (timeout
->tv_sec
* 1000 + timeout
->tv_usec
/ 1000);
81 for (fd
= 0; fd
< n
; ++fd
)
83 HANDLE read
= NULL
, except
= NULL
;
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
));
91 if ((!readfds
|| !FD_ISSET (fd
, readfds
))
92 && (!exceptfds
|| !FD_ISSET (fd
, exceptfds
)))
95 scb
= serial_for_fd (fd
);
98 serial_wait_handle (scb
, &read
, &except
);
99 scbs
[num_scbs
++] = scb
;
103 read
= (HANDLE
) _get_osfhandle (fd
);
107 never_handle
= CreateEvent (0, FALSE
, FALSE
, 0);
109 except
= never_handle
;
112 if (readfds
&& FD_ISSET (fd
, readfds
))
114 gdb_assert (num_handles
< MAXIMUM_WAIT_OBJECTS
);
115 handles
[num_handles
++] = read
;
118 if (exceptfds
&& FD_ISSET (fd
, exceptfds
))
120 gdb_assert (num_handles
< MAXIMUM_WAIT_OBJECTS
);
121 handles
[num_handles
++] = except
;
125 gdb_assert (num_handles
<= MAXIMUM_WAIT_OBJECTS
);
127 event
= WaitForMultipleObjects (num_handles
,
131 ? (timeout
->tv_sec
* 1000
132 + timeout
->tv_usec
/ 1000)
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
));
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
]);
142 if (event
== WAIT_FAILED
)
144 if (event
== WAIT_TIMEOUT
)
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
)
153 if ((!readfds
|| !FD_ISSET (fd
, readfds
))
154 && (!exceptfds
|| !FD_ISSET (fd
, exceptfds
)))
157 if (readfds
&& FD_ISSET (fd
, readfds
))
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
);
168 if (exceptfds
&& FD_ISSET (fd
, exceptfds
))
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
);
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. */
187 rgb_to_16colors (const ui_file_style::color
&color
)
193 for (int i
= 0; i
< 3; i
++)
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);
208 /* Zero if not yet initialized, 1 if stdout is a console device, else -1. */
209 static int mingw_console_initialized
;
211 /* Handle to stdout . */
212 static HANDLE hstdout
= INVALID_HANDLE_VALUE
;
214 /* Text attribute to use for normal text (the "none" pseudo-color). */
215 static SHORT norm_attr
;
217 /* The most recently applied style. */
218 static ui_file_style last_style
;
220 /* Alternative for the libc 'fputs' which handles embedded SGR
221 sequences in support of styling. */
224 gdb_console_fputs (const char *linebuf
, FILE *fstream
)
226 if (!mingw_console_initialized
)
228 hstdout
= (HANDLE
)_get_osfhandle (fileno (fstream
));
230 CONSOLE_SCREEN_BUFFER_INFO csbi
;
232 if (hstdout
!= INVALID_HANDLE_VALUE
233 && GetConsoleMode (hstdout
, &cmode
) != 0
234 && GetConsoleScreenBufferInfo (hstdout
, &csbi
))
236 norm_attr
= csbi
.wAttributes
;
237 mingw_console_initialized
= 1;
239 else if (hstdout
!= INVALID_HANDLE_VALUE
)
240 mingw_console_initialized
= -1; /* valid, but not a console device */
242 /* If our stdout is not a console device, let the default 'fputs'
244 if (mingw_console_initialized
<= 0)
247 /* Mapping between 8 ANSI colors and Windows console attributes. */
248 static int fg_color
[] = {
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 */
258 static int bg_color
[] = {
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 */
269 ui_file_style style
= last_style
;
273 for ( ; (c
= *linebuf
) != 0; linebuf
+= n_read
)
278 bool parsed
= style
.parse (linebuf
, &n_read
);
279 if (n_read
<= 0) /* should never happen */
283 /* This means we silently swallow SGR sequences we
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
;
292 fgcolor
= norm_attr
& 15;
293 else if (fg
.is_basic ())
294 fgcolor
= fg_color
[fg
.get_value () & 15];
296 fgcolor
= rgb_to_16colors (fg
);
298 bgcolor
= norm_attr
& (15 << 4);
299 else if (bg
.is_basic ())
300 bgcolor
= bg_color
[bg
.get_value () & 15];
302 bgcolor
= rgb_to_16colors (bg
) << 4;
305 switch (style
.get_intensity ())
307 case ui_file_style::NORMAL
:
308 case ui_file_style::DIM
:
311 case ui_file_style::BOLD
:
315 gdb_assert_not_reached ("invalid intensity");
319 if (style
.is_reverse ())
324 /* Construct the attribute. */
328 fgcolor
= (bgcolor
>> 4);
332 fgcolor
|= FOREGROUND_INTENSITY
;
334 SHORT attr
= (bgcolor
& (15 << 4)) | (fgcolor
& 15);
336 /* Apply the attribute. */
337 SetConsoleTextAttribute (hstdout
, attr
);
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. */
350 CONSOLE_SCREEN_BUFFER_INFO csbi
;
353 GetConsoleScreenBufferInfo (hstdout
, &csbi
);
355 if (csbi
.wAttributes
!= norm_attr
)
357 start_pos
= csbi
.dwCursorPosition
;
358 nchars
= csbi
.dwSize
.X
- start_pos
.X
;
360 FillConsoleOutputAttribute (hstdout
, norm_attr
, nchars
,
361 start_pos
, &written
);
362 FillConsoleOutputCharacter (hstdout
, ' ', nchars
,
363 start_pos
, &written
);
375 /* See inferior.h. */
378 sharing_input_terminal (int pid
)
380 std::vector
<DWORD
> results (10);
384 len
= GetConsoleProcessList (results
.data (), results
.size ());
385 /* Note that LEN == 0 is a failure, but we can treat it the same
387 if (len
<= results
.size ())
390 results
.resize (len
);
392 /* In case the vector was too big. */
393 results
.resize (len
);
394 if (std::find (results
.begin (), results
.end (), pid
) != results
.end ())
396 /* The pid is in the list sharing the console, so don't
397 interrupt the inferior -- it will get the signal itself. */
401 return TRIBOOL_FALSE
;
404 /* Current C-c handler. */
405 static c_c_handler_ftype
*current_handler
;
407 /* The Windows callback that forwards requests to the C-c handler. */
409 ctrl_c_handler (DWORD event_type
)
411 if (event_type
== CTRL_BREAK_EVENT
|| event_type
== CTRL_C_EVENT
)
413 if (current_handler
!= SIG_IGN
)
414 current_handler (SIGINT
);
421 /* See inferior.h. */
424 install_sigint_handler (c_c_handler_ftype
*fn
)
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;
432 SetConsoleCtrlHandler (ctrl_c_handler
, FALSE
);
433 SetConsoleCtrlHandler (ctrl_c_handler
, TRUE
);
436 c_c_handler_ftype
*result
= current_handler
;
437 current_handler
= fn
;