Commit | Line | Data |
---|---|---|
121ce6e5 DJ |
1 | /* Host support routines for MinGW, for GDB, the GNU debugger. |
2 | ||
42a4f53d | 3 | Copyright (C) 2006-2019 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" |
b803fb0f | 23 | #include "event-loop.h" |
121ce6e5 | 24 | |
0ea3f30e | 25 | #include "gdb_select.h" |
121ce6e5 DJ |
26 | |
27 | #include <windows.h> | |
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 | ||
32 | char * | |
33 | windows_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 | ||
49 | int | |
50 | gdb_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 DJ |
66 | |
67 | num_ready = 0; | |
68 | num_handles = 0; | |
4577549b | 69 | num_scbs = 0; |
0ea3f30e DJ |
70 | for (fd = 0; fd < n; ++fd) |
71 | { | |
72 | HANDLE read = NULL, except = NULL; | |
73 | struct serial *scb; | |
74 | ||
75 | /* There is no support yet for WRITEFDS. At present, this isn't | |
76 | used by GDB -- but we do not want to silently ignore WRITEFDS | |
77 | if something starts using it. */ | |
78 | gdb_assert (!writefds || !FD_ISSET (fd, writefds)); | |
79 | ||
98739726 DJ |
80 | if ((!readfds || !FD_ISSET (fd, readfds)) |
81 | && (!exceptfds || !FD_ISSET (fd, exceptfds))) | |
0ea3f30e | 82 | continue; |
0ea3f30e DJ |
83 | |
84 | scb = serial_for_fd (fd); | |
85 | if (scb) | |
4577549b DJ |
86 | { |
87 | serial_wait_handle (scb, &read, &except); | |
88 | scbs[num_scbs++] = scb; | |
89 | } | |
0ea3f30e DJ |
90 | |
91 | if (read == NULL) | |
4577549b | 92 | read = (HANDLE) _get_osfhandle (fd); |
0ea3f30e DJ |
93 | if (except == NULL) |
94 | { | |
95 | if (!never_handle) | |
96 | never_handle = CreateEvent (0, FALSE, FALSE, 0); | |
97 | ||
98 | except = never_handle; | |
99 | } | |
100 | ||
98739726 | 101 | if (readfds && FD_ISSET (fd, readfds)) |
0ea3f30e DJ |
102 | { |
103 | gdb_assert (num_handles < MAXIMUM_WAIT_OBJECTS); | |
104 | handles[num_handles++] = read; | |
105 | } | |
106 | ||
98739726 | 107 | if (exceptfds && FD_ISSET (fd, exceptfds)) |
0ea3f30e DJ |
108 | { |
109 | gdb_assert (num_handles < MAXIMUM_WAIT_OBJECTS); | |
110 | handles[num_handles++] = except; | |
111 | } | |
112 | } | |
0ea3f30e | 113 | |
585a46a2 | 114 | gdb_assert (num_handles <= MAXIMUM_WAIT_OBJECTS); |
0ea3f30e DJ |
115 | |
116 | event = WaitForMultipleObjects (num_handles, | |
117 | handles, | |
118 | FALSE, | |
119 | timeout | |
120 | ? (timeout->tv_sec * 1000 | |
121 | + timeout->tv_usec / 1000) | |
122 | : INFINITE); | |
123 | /* EVENT can only be a value in the WAIT_ABANDONED_0 range if the | |
124 | HANDLES included an abandoned mutex. Since GDB doesn't use | |
125 | mutexes, that should never occur. */ | |
126 | gdb_assert (!(WAIT_ABANDONED_0 <= event | |
127 | && event < WAIT_ABANDONED_0 + num_handles)); | |
4577549b DJ |
128 | /* We no longer need the helper threads to check for activity. */ |
129 | for (indx = 0; indx < num_scbs; ++indx) | |
130 | serial_done_wait_handle (scbs[indx]); | |
0ea3f30e DJ |
131 | if (event == WAIT_FAILED) |
132 | return -1; | |
133 | if (event == WAIT_TIMEOUT) | |
134 | return 0; | |
135 | /* Run through the READFDS, clearing bits corresponding to descriptors | |
136 | for which input is unavailable. */ | |
137 | h = handles[event - WAIT_OBJECT_0]; | |
138 | for (fd = 0, indx = 0; fd < n; ++fd) | |
139 | { | |
140 | HANDLE fd_h; | |
c3e2b812 | 141 | |
98739726 DJ |
142 | if ((!readfds || !FD_ISSET (fd, readfds)) |
143 | && (!exceptfds || !FD_ISSET (fd, exceptfds))) | |
c3e2b812 | 144 | continue; |
0ea3f30e | 145 | |
98739726 | 146 | if (readfds && FD_ISSET (fd, readfds)) |
0ea3f30e DJ |
147 | { |
148 | fd_h = handles[indx++]; | |
149 | /* This handle might be ready, even though it wasn't the handle | |
150 | returned by WaitForMultipleObjects. */ | |
151 | if (fd_h != h && WaitForSingleObject (fd_h, 0) != WAIT_OBJECT_0) | |
152 | FD_CLR (fd, readfds); | |
153 | else | |
154 | num_ready++; | |
155 | } | |
156 | ||
98739726 | 157 | if (exceptfds && FD_ISSET (fd, exceptfds)) |
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, exceptfds); | |
164 | else | |
165 | num_ready++; | |
166 | } | |
167 | } | |
168 | ||
169 | return num_ready; | |
170 | } | |
e4adb939 EZ |
171 | |
172 | /* Map COLOR's RGB triplet, with 8 bits per component, into 16 Windows | |
173 | console colors, where each component has just 1 bit, plus a single | |
174 | intensity bit which affects all 3 components. */ | |
175 | static int | |
176 | rgb_to_16colors (const ui_file_style::color &color) | |
177 | { | |
178 | uint8_t rgb[3]; | |
179 | color.get_rgb (rgb); | |
180 | ||
181 | int retval = 0; | |
182 | for (int i = 0; i < 3; i++) | |
183 | { | |
184 | /* Subdivide 256 possible values of each RGB component into 3 | |
185 | regions: no color, normal color, bright color. 256 / 3 = 85, | |
186 | but ui-style.c follows xterm and uses 92 for R and G | |
187 | components of the bright-blue color, so we bias the divisor a | |
188 | bit to have the bright colors between 9 and 15 identical to | |
189 | what ui-style.c expects. */ | |
190 | int bits = rgb[i] / 93; | |
191 | retval |= ((bits > 0) << (2 - i)) | ((bits > 1) << 3); | |
192 | } | |
193 | ||
194 | return retval; | |
195 | } | |
196 | ||
197 | /* Zero if not yet initialized, 1 if stdout is a console device, else -1. */ | |
198 | static int mingw_console_initialized; | |
199 | ||
200 | /* Handle to stdout . */ | |
201 | static HANDLE hstdout = INVALID_HANDLE_VALUE; | |
202 | ||
203 | /* Text attribute to use for normal text (the "none" pseudo-color). */ | |
204 | static SHORT norm_attr; | |
205 | ||
206 | /* The most recently applied style. */ | |
207 | static ui_file_style last_style; | |
208 | ||
209 | /* Alternative for the libc 'fputs' which handles embedded SGR | |
210 | sequences in support of styling. */ | |
211 | ||
212 | int | |
213 | gdb_console_fputs (const char *linebuf, FILE *fstream) | |
214 | { | |
215 | if (!mingw_console_initialized) | |
216 | { | |
217 | hstdout = (HANDLE)_get_osfhandle (fileno (fstream)); | |
218 | DWORD cmode; | |
219 | CONSOLE_SCREEN_BUFFER_INFO csbi; | |
220 | ||
221 | if (hstdout != INVALID_HANDLE_VALUE | |
222 | && GetConsoleMode (hstdout, &cmode) != 0 | |
223 | && GetConsoleScreenBufferInfo (hstdout, &csbi)) | |
224 | { | |
225 | norm_attr = csbi.wAttributes; | |
226 | mingw_console_initialized = 1; | |
227 | } | |
228 | else if (hstdout != INVALID_HANDLE_VALUE) | |
229 | mingw_console_initialized = -1; /* valid, but not a console device */ | |
230 | } | |
231 | /* If our stdout is not a console device, let the default 'fputs' | |
232 | handle the task. */ | |
233 | if (mingw_console_initialized <= 0) | |
234 | return 0; | |
235 | ||
236 | /* Mapping between 8 ANSI colors and Windows console attributes. */ | |
237 | static int fg_color[] = { | |
238 | 0, /* black */ | |
239 | FOREGROUND_RED, /* red */ | |
240 | FOREGROUND_GREEN, /* green */ | |
241 | FOREGROUND_GREEN | FOREGROUND_RED, /* yellow */ | |
242 | FOREGROUND_BLUE, /* blue */ | |
243 | FOREGROUND_BLUE | FOREGROUND_RED, /* magenta */ | |
244 | FOREGROUND_BLUE | FOREGROUND_GREEN, /* cyan */ | |
245 | FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE /* gray */ | |
246 | }; | |
247 | static int bg_color[] = { | |
248 | 0, /* black */ | |
249 | BACKGROUND_RED, /* red */ | |
250 | BACKGROUND_GREEN, /* green */ | |
251 | BACKGROUND_GREEN | BACKGROUND_RED, /* yellow */ | |
252 | BACKGROUND_BLUE, /* blue */ | |
253 | BACKGROUND_BLUE | BACKGROUND_RED, /* magenta */ | |
254 | BACKGROUND_BLUE | BACKGROUND_GREEN, /* cyan */ | |
255 | BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE /* gray */ | |
256 | }; | |
257 | ||
258 | ui_file_style style = last_style; | |
259 | unsigned char c; | |
260 | size_t n_read; | |
261 | ||
262 | for ( ; (c = *linebuf) != 0; linebuf += n_read) | |
263 | { | |
264 | if (c == '\033') | |
265 | { | |
266 | fflush (fstream); | |
267 | bool parsed = style.parse (linebuf, &n_read); | |
268 | if (n_read <= 0) /* should never happen */ | |
269 | n_read = 1; | |
270 | if (!parsed) | |
271 | { | |
272 | /* This means we silently swallow SGR sequences we | |
273 | cannot parse. */ | |
274 | continue; | |
275 | } | |
276 | /* Colors. */ | |
277 | const ui_file_style::color &fg = style.get_foreground (); | |
278 | const ui_file_style::color &bg = style.get_background (); | |
279 | int fgcolor, bgcolor, bright, inverse; | |
280 | if (fg.is_none ()) | |
281 | fgcolor = norm_attr & 15; | |
282 | else if (fg.is_basic ()) | |
283 | fgcolor = fg_color[fg.get_value () & 15]; | |
284 | else | |
285 | fgcolor = rgb_to_16colors (fg); | |
286 | if (bg.is_none ()) | |
287 | bgcolor = norm_attr & (15 << 4); | |
288 | else if (bg.is_basic ()) | |
289 | bgcolor = bg_color[bg.get_value () & 15]; | |
290 | else | |
291 | bgcolor = rgb_to_16colors (bg) << 4; | |
292 | ||
293 | /* Intensity. */ | |
294 | switch (style.get_intensity ()) | |
295 | { | |
296 | case ui_file_style::NORMAL: | |
297 | case ui_file_style::DIM: | |
298 | bright = 0; | |
299 | break; | |
300 | case ui_file_style::BOLD: | |
301 | bright = 1; | |
302 | break; | |
303 | default: | |
304 | gdb_assert_not_reached ("invalid intensity"); | |
305 | } | |
306 | ||
307 | /* Inverse video. */ | |
308 | if (style.is_reverse ()) | |
309 | inverse = 1; | |
310 | else | |
311 | inverse = 0; | |
312 | ||
313 | /* Construct the attribute. */ | |
314 | if (inverse) | |
315 | { | |
316 | int t = fgcolor; | |
317 | fgcolor = (bgcolor >> 4); | |
318 | bgcolor = (t << 4); | |
319 | } | |
320 | if (bright) | |
321 | fgcolor |= FOREGROUND_INTENSITY; | |
322 | ||
323 | SHORT attr = (bgcolor & (15 << 4)) | (fgcolor & 15); | |
324 | ||
325 | /* Apply the attribute. */ | |
326 | SetConsoleTextAttribute (hstdout, attr); | |
327 | } | |
328 | else | |
329 | { | |
330 | /* When we are about to write newline, we need to clear to | |
331 | EOL with the normal attribute, to avoid spilling the | |
332 | colors to the next screen line. We assume here that no | |
333 | non-default attribute extends beyond the newline. */ | |
334 | if (c == '\n') | |
335 | { | |
336 | DWORD nchars; | |
337 | COORD start_pos; | |
338 | DWORD written; | |
339 | CONSOLE_SCREEN_BUFFER_INFO csbi; | |
340 | ||
341 | fflush (fstream); | |
342 | GetConsoleScreenBufferInfo (hstdout, &csbi); | |
343 | ||
344 | if (csbi.wAttributes != norm_attr) | |
345 | { | |
346 | start_pos = csbi.dwCursorPosition; | |
347 | nchars = csbi.dwSize.X - start_pos.X; | |
348 | ||
349 | FillConsoleOutputAttribute (hstdout, norm_attr, nchars, | |
350 | start_pos, &written); | |
351 | FillConsoleOutputCharacter (hstdout, ' ', nchars, | |
352 | start_pos, &written); | |
353 | } | |
354 | } | |
355 | fputc (c, fstream); | |
356 | n_read = 1; | |
357 | } | |
358 | } | |
359 | ||
360 | last_style = style; | |
361 | return 1; | |
362 | } |