]>
Commit | Line | Data |
---|---|---|
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 | ||
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 | ||
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 | ||
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; | |
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. */ | |
187 | static int | |
188 | rgb_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. */ | |
210 | static int mingw_console_initialized; | |
211 | ||
212 | /* Handle to stdout . */ | |
213 | static HANDLE hstdout = INVALID_HANDLE_VALUE; | |
214 | ||
215 | /* Text attribute to use for normal text (the "none" pseudo-color). */ | |
216 | static SHORT norm_attr; | |
217 | ||
218 | /* The most recently applied style. */ | |
219 | static ui_file_style last_style; | |
220 | ||
221 | /* Alternative for the libc 'fputs' which handles embedded SGR | |
222 | sequences in support of styling. */ | |
223 | ||
224 | int | |
225 | gdb_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 | ||
378 | tribool | |
379 | sharing_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. */ | |
406 | static c_c_handler_ftype *current_handler; | |
407 | ||
408 | /* The Windows callback that forwards requests to the C-c handler. */ | |
409 | static BOOL WINAPI | |
410 | ctrl_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 | ||
424 | c_c_handler_ftype * | |
425 | install_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 | } |