mingw-hdep.c revision 1.9
1/* Host support routines for MinGW, for GDB, the GNU debugger. 2 3 Copyright (C) 2006-2020 Free Software Foundation, Inc. 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 9 the Free Software Foundation; either version 3 of the License, or 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 18 along with this program. If not, see <http://www.gnu.org/licenses/>. */ 19 20#include "defs.h" 21#include "main.h" 22#include "serial.h" 23#include "gdbsupport/event-loop.h" 24 25#include "gdbsupport/gdb_select.h" 26 27#include <windows.h> 28 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 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; 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; 63 int fd; 64 int num_ready; 65 size_t indx; 66 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 78 num_ready = 0; 79 num_handles = 0; 80 num_scbs = 0; 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 91 if ((!readfds || !FD_ISSET (fd, readfds)) 92 && (!exceptfds || !FD_ISSET (fd, exceptfds))) 93 continue; 94 95 scb = serial_for_fd (fd); 96 if (scb) 97 { 98 serial_wait_handle (scb, &read, &except); 99 scbs[num_scbs++] = scb; 100 } 101 102 if (read == NULL) 103 read = (HANDLE) _get_osfhandle (fd); 104 if (except == NULL) 105 { 106 if (!never_handle) 107 never_handle = CreateEvent (0, FALSE, FALSE, 0); 108 109 except = never_handle; 110 } 111 112 if (readfds && FD_ISSET (fd, readfds)) 113 { 114 gdb_assert (num_handles < MAXIMUM_WAIT_OBJECTS); 115 handles[num_handles++] = read; 116 } 117 118 if (exceptfds && FD_ISSET (fd, exceptfds)) 119 { 120 gdb_assert (num_handles < MAXIMUM_WAIT_OBJECTS); 121 handles[num_handles++] = except; 122 } 123 } 124 125 gdb_assert (num_handles <= MAXIMUM_WAIT_OBJECTS); 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)); 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) 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; 152 153 if ((!readfds || !FD_ISSET (fd, readfds)) 154 && (!exceptfds || !FD_ISSET (fd, exceptfds))) 155 continue; 156 157 if (readfds && FD_ISSET (fd, readfds)) 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 168 if (exceptfds && FD_ISSET (fd, exceptfds)) 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} 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} 374