From 0ea3f30e219bd42259f09f68bcd605bf4ed4a1ea Mon Sep 17 00:00:00 2001 From: Daniel Jacobowitz Date: Fri, 10 Feb 2006 22:01:43 +0000 Subject: [PATCH] * NEWS: Mention native Windows support. * Makefile.in (gdb_select_h, ser_tcp_h): New. (ALLDEPFILES): Add ser-mingw.c. (event-loop.o, inflow.o, mingw-hdep.o, posix-hdep.o, ser-base.o) (ser-tcp.o, ser-unix.o): Update. (ser-mingw.o): New rule. * configure: Regenerated. * configure.ac: Add ser-mingw.o for mingw32. * ser-mingw.c: New file. * event-loop.c: Include "gdb_select.h". (gdb_select): Remove, moved to mingw-hdep.c and posix-hdep.c. * ser-base.c: Include "gdb_select.h". (ser_base_wait_for): Use gdb_select. * serial.c (serial_for_fd): New function. (serial_fdopen): Try "terminal" before "hardwire". Initialize the allocated struct serial. (serial_wait_handle): New function. * serial.h (serial_for_fd, serial_wait_handle): New prototypes. (struct serial_ops) [USE_WIN32API]: Add wait_handle. * gdb_select.h: New file. * ser-tcp.c: Include "ser-tcp.h". Remove unused "ser-unix.h" include. (net_close, net_read_prim, net_write_prim): Make global. (net_open): Likewise. Pass an exception set to select. Whitespace fix. Document why we can not use gdb_select. (_initialize_ser_tcp) [USE_WIN32API]: Do not register TCP support here. * ser-tcp.h: New file. * inflow.c (gdb_has_a_terminal): Don't initialize stdin_serial here. (handle_sigio): Use gdb_select. (initialize_stdin_serial): New function. * terminal.h (initialize_stdin_serial): New prototype. * top.c (gdb_init): Call initialize_stdin_serial. * mingw-hdep.c (gdb_select): New function, moved from gdb_select in event-loop.c. Add exception condition support. Use serial_for_fd and serial_wait_handle. Fix timeout handling. * posix-hdep.c: Include "gdb_select.h". (gdb_select): New function. * remote-st.c (connect_command): Use gdb_select. * ser-unix.c: Include "gdb_select.h". (hardwire_send_break, wait_for): Use gdb_select. --- gdb/ChangeLog | 42 +++ gdb/Makefile.in | 21 +- gdb/NEWS | 6 + gdb/configure | 2 +- gdb/configure.ac | 5 +- gdb/event-loop.c | 95 +----- gdb/gdb_select.h | 37 +++ gdb/inflow.c | 21 +- gdb/mingw-hdep.c | 124 ++++++++ gdb/posix-hdep.c | 10 + gdb/remote-st.c | 2 +- gdb/ser-base.c | 7 +- gdb/ser-mingw.c | 796 +++++++++++++++++++++++++++++++++++++++++++++++ gdb/ser-tcp.c | 41 ++- gdb/ser-tcp.h | 32 ++ gdb/ser-unix.c | 7 +- gdb/serial.c | 37 ++- gdb/serial.h | 26 +- gdb/terminal.h | 6 +- gdb/top.c | 2 + 20 files changed, 1181 insertions(+), 138 deletions(-) create mode 100644 gdb/gdb_select.h create mode 100644 gdb/ser-mingw.c create mode 100644 gdb/ser-tcp.h diff --git a/gdb/ChangeLog b/gdb/ChangeLog index c73df203a1..400104d687 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,45 @@ +2006-02-10 Daniel Jacobowitz + + * NEWS: Mention native Windows support. + * Makefile.in (gdb_select_h, ser_tcp_h): New. + (ALLDEPFILES): Add ser-mingw.c. + (event-loop.o, inflow.o, mingw-hdep.o, posix-hdep.o, ser-base.o) + (ser-tcp.o, ser-unix.o): Update. + (ser-mingw.o): New rule. + * configure: Regenerated. + * configure.ac: Add ser-mingw.o for mingw32. + * ser-mingw.c: New file. + * event-loop.c: Include "gdb_select.h". + (gdb_select): Remove, moved to mingw-hdep.c and posix-hdep.c. + * ser-base.c: Include "gdb_select.h". + (ser_base_wait_for): Use gdb_select. + * serial.c (serial_for_fd): New function. + (serial_fdopen): Try "terminal" before "hardwire". Initialize + the allocated struct serial. + (serial_wait_handle): New function. + * serial.h (serial_for_fd, serial_wait_handle): New prototypes. + (struct serial_ops) [USE_WIN32API]: Add wait_handle. + * gdb_select.h: New file. + * ser-tcp.c: Include "ser-tcp.h". Remove unused "ser-unix.h" include. + (net_close, net_read_prim, net_write_prim): Make global. + (net_open): Likewise. Pass an exception set to select. Whitespace fix. + Document why we can not use gdb_select. + (_initialize_ser_tcp) [USE_WIN32API]: Do not register TCP support here. + * ser-tcp.h: New file. + * inflow.c (gdb_has_a_terminal): Don't initialize stdin_serial here. + (handle_sigio): Use gdb_select. + (initialize_stdin_serial): New function. + * terminal.h (initialize_stdin_serial): New prototype. + * top.c (gdb_init): Call initialize_stdin_serial. + * mingw-hdep.c (gdb_select): New function, moved from gdb_select in + event-loop.c. Add exception condition support. Use serial_for_fd + and serial_wait_handle. Fix timeout handling. + * posix-hdep.c: Include "gdb_select.h". + (gdb_select): New function. + * remote-st.c (connect_command): Use gdb_select. + * ser-unix.c: Include "gdb_select.h". + (hardwire_send_break, wait_for): Use gdb_select. + 2006-02-10 Daniel Jacobowitz * Makefile.in (mingw-hdep.o, posix-hdep.o): New dependencies. diff --git a/gdb/Makefile.in b/gdb/Makefile.in index 9c0f30bbe4..779c9d0766 100644 --- a/gdb/Makefile.in +++ b/gdb/Makefile.in @@ -694,6 +694,7 @@ gdb_obstack_h = gdb_obstack.h $(obstack_h) gdb_proc_service_h = gdb_proc_service.h $(gregset_h) gdb_ptrace_h = gdb_ptrace.h gdb_regex_h = gdb_regex.h $(xregex_h) +gdb_select_h = gdb_select.h gdb_stabs_h = gdb-stabs.h gdb_stat_h = gdb_stat.h gdb_string_h = gdb_string.h @@ -767,6 +768,7 @@ scm_tags_h = scm-tags.h sentinel_frame_h = sentinel-frame.h serial_h = serial.h ser_base_h = ser-base.h +ser_tcp_h = ser-tcp.h ser_unix_h = ser-unix.h shnbsd_tdep_h = shnbsd-tdep.h sh_tdep_h = sh-tdep.h @@ -1445,7 +1447,7 @@ ALLDEPFILES = \ remote-st.c remote-utils.c dcache.c \ rs6000-nat.c rs6000-tdep.c \ s390-tdep.c s390-nat.c \ - ser-go32.c ser-pipe.c ser-tcp.c \ + ser-go32.c ser-pipe.c ser-tcp.c ser-mingw.c \ sh-tdep.c sh64-tdep.c shnbsd-tdep.c shnbsd-nat.c \ sol2-tdep.c \ solib-irix.c solib-svr4.c solib-sunos.c \ @@ -1922,7 +1924,7 @@ eval.o: eval.c $(defs_h) $(gdb_string_h) $(symtab_h) $(gdbtypes_h) \ $(f_lang_h) $(cp_abi_h) $(infcall_h) $(objc_lang_h) $(block_h) \ $(parser_defs_h) $(cp_support_h) event-loop.o: event-loop.c $(defs_h) $(event_loop_h) $(event_top_h) \ - $(gdb_string_h) $(exceptions_h) $(gdb_assert_h) + $(gdb_string_h) $(exceptions_h) $(gdb_assert_h) $(gdb_select_h) event-top.o: event-top.c $(defs_h) $(top_h) $(inferior_h) $(target_h) \ $(terminal_h) $(event_loop_h) $(event_top_h) $(interps_h) \ $(exceptions_h) $(gdbcmd_h) $(readline_h) $(readline_history_h) @@ -2129,7 +2131,7 @@ inf-loop.o: inf-loop.c $(defs_h) $(inferior_h) $(target_h) $(event_loop_h) \ $(event_top_h) $(inf_loop_h) $(remote_h) $(exceptions_h) inflow.o: inflow.c $(defs_h) $(frame_h) $(inferior_h) $(command_h) \ $(serial_h) $(terminal_h) $(target_h) $(gdbthread_h) $(gdb_string_h) \ - $(inflow_h) + $(inflow_h) $(gdb_select_h) inf-ptrace.o: inf-ptrace.c $(defs_h) $(command_h) $(inferior_h) $(inflow_h) \ $(gdbcore_h) $(regcache_h) $(gdb_assert_h) \ $(gdb_string_h) $(gdb_ptrace_h) $(gdb_wait_h) $(inf_child_h) @@ -2282,7 +2284,8 @@ memattr.o: memattr.c $(defs_h) $(command_h) $(gdbcmd_h) $(memattr_h) \ $(target_h) $(value_h) $(language_h) $(gdb_string_h) mem-break.o: mem-break.c $(defs_h) $(symtab_h) $(breakpoint_h) $(inferior_h) \ $(target_h) -mingw-hdep.o: mingw-hdep.c $(defs_h) $(gdb_string_h) +mingw-hdep.o: mingw-hdep.c $(defs_h) $(serial_h) $(gdb_assert_h) \ + $(gdb_select_h) $(gdb_string_h) minsyms.o: minsyms.c $(defs_h) $(gdb_string_h) $(symtab_h) $(bfd_h) \ $(symfile_h) $(objfiles_h) $(demangle_h) $(value_h) $(cp_abi_h) mips64obsd-nat.o: mips64obsd-nat.c $(defs_h) $(inferior_h) $(regcache_h) \ @@ -2378,7 +2381,7 @@ p-exp.o: p-exp.c $(defs_h) $(gdb_string_h) $(expression_h) $(value_h) \ p-lang.o: p-lang.c $(defs_h) $(gdb_string_h) $(symtab_h) $(gdbtypes_h) \ $(expression_h) $(parser_defs_h) $(language_h) $(p_lang_h) \ $(valprint_h) $(value_h) -posix-hdep.o: posix-hdep.c $(defs_h) $(gdb_string_h) +posix-hdep.o: posix-hdep.c $(defs_h) $(gdb_string_h) $(gdb_select_h) ppc-bdm.o: ppc-bdm.c $(defs_h) $(gdbcore_h) $(gdb_string_h) $(frame_h) \ $(inferior_h) $(bfd_h) $(symfile_h) $(target_h) $(gdbcmd_h) \ $(objfiles_h) $(gdb_stabs_h) $(serial_h) $(ocd_h) $(ppc_tdep_h) \ @@ -2517,13 +2520,15 @@ ser-e7kpc.o: ser-e7kpc.c $(defs_h) $(serial_h) $(gdb_string_h) ser-go32.o: ser-go32.c $(defs_h) $(gdbcmd_h) $(serial_h) $(gdb_string_h) serial.o: serial.c $(defs_h) $(serial_h) $(gdb_string_h) $(gdbcmd_h) ser-base.o: ser-base.c $(defs_h) $(serial_h) $(ser_base_h) $(event_loop_h) \ - $(gdb_string_h) + $(gdb_select_h) $(gdb_string_h) ser-pipe.o: ser-pipe.c $(defs_h) $(serial_h) $(ser_base_h) $(ser_unix_h) \ $(gdb_vfork_h) $(gdb_string_h) -ser-tcp.o: ser-tcp.c $(defs_h) $(serial_h) $(ser_base_h) $(ser_unix_h) \ +ser-tcp.o: ser-tcp.c $(defs_h) $(serial_h) $(ser_base_h) $(ser_tcp_h) \ $(gdb_string_h) ser-unix.o: ser-unix.c $(defs_h) $(serial_h) $(ser_base_h) $(ser_unix_h) \ - $(terminal_h) $(gdb_string_h) + $(terminal_h) $(gdb_select_h) $(gdb_string_h) +ser-mingw.o: ser-mingw.c $(defs_h) $(serial_h) $(ser_base_h) \ + $(ser_tcp_h) $(gdb_assert_h) $(gdb_string_h) sh3-rom.o: sh3-rom.c $(defs_h) $(gdbcore_h) $(target_h) $(monitor_h) \ $(serial_h) $(srec_h) $(arch_utils_h) $(regcache_h) $(gdb_string_h) \ $(sh_tdep_h) diff --git a/gdb/NEWS b/gdb/NEWS index 900442da1e..c42313cde2 100644 --- a/gdb/NEWS +++ b/gdb/NEWS @@ -41,6 +41,12 @@ detach-fork Delete a fork from the list of forks Morpho Technologies ms2 ms1-elf +* Improved Windows host support + +GDB now builds as a cross debugger hosted on i686-mingw32, including +native console support, and remote communications using either +network sockets or serial ports. + * REMOVED features The ARM rdi-share module. diff --git a/gdb/configure b/gdb/configure index d9ea423227..cf547b72d4 100755 --- a/gdb/configure +++ b/gdb/configure @@ -20097,7 +20097,7 @@ SER_HARDWIRE="ser-base.o ser-unix.o ser-pipe.o ser-tcp.o" case ${host} in *go32* ) SER_HARDWIRE=ser-go32.o ;; *djgpp* ) SER_HARDWIRE=ser-go32.o ;; - *mingw32*) SER_HARDWIRE="ser-base.o ser-tcp.o" ;; + *mingw32*) SER_HARDWIRE="ser-base.o ser-tcp.o ser-mingw.o" ;; esac diff --git a/gdb/configure.ac b/gdb/configure.ac index 55dc2be75b..1861275a2d 100644 --- a/gdb/configure.ac +++ b/gdb/configure.ac @@ -1,5 +1,6 @@ dnl Autoconf configure script for GDB, the GNU debugger. -dnl Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004 +dnl Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, +dnl 2005, 2006 dnl Free Software Foundation, Inc. dnl dnl This file is part of GDB. @@ -1202,7 +1203,7 @@ SER_HARDWIRE="ser-base.o ser-unix.o ser-pipe.o ser-tcp.o" case ${host} in *go32* ) SER_HARDWIRE=ser-go32.o ;; *djgpp* ) SER_HARDWIRE=ser-go32.o ;; - *mingw32*) SER_HARDWIRE="ser-base.o ser-tcp.o" ;; + *mingw32*) SER_HARDWIRE="ser-base.o ser-tcp.o ser-mingw.o" ;; esac AC_SUBST(SER_HARDWIRE) diff --git a/gdb/event-loop.c b/gdb/event-loop.c index 4f859b115c..671528f25b 100644 --- a/gdb/event-loop.c +++ b/gdb/event-loop.c @@ -1,5 +1,6 @@ /* Event loop machinery for GDB, the GNU debugger. - Copyright (C) 1999, 2000, 2001, 2002 Free Software Foundation, Inc. + Copyright (C) 1999, 2000, 2001, 2002, 2005, 2006 + Free Software Foundation, Inc. Written by Elena Zannoni of Cygnus Solutions. This file is part of GDB. @@ -37,6 +38,7 @@ #include #include "exceptions.h" #include "gdb_assert.h" +#include "gdb_select.h" typedef struct gdb_event gdb_event; typedef void (event_handler_func) (int); @@ -731,97 +733,6 @@ handle_file_event (int event_file_desc) } } -/* Wrapper for select. This function is not yet exported from this - file because it is not sufficiently general. For example, - ser-base.c uses select to check for socket activity, and this - function does not support sockets under Windows, so we do not want - to use gdb_select in ser-base.c. */ - -static int -gdb_select (int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, - struct timeval *timeout) -{ -#ifdef USE_WIN32API - HANDLE handles[MAXIMUM_WAIT_OBJECTS]; - HANDLE h; - DWORD event; - DWORD num_handles; - int fd; - int num_ready; - - num_ready = 0; - num_handles = 0; - for (fd = 0; fd < n; ++fd) - { - /* There is no support yet for WRITEFDS. At present, this isn't - used by GDB -- but we do not want to silently ignore WRITEFDS - if something starts using it. */ - gdb_assert (!FD_ISSET (fd, writefds)); - if (!FD_ISSET (fd, readfds) - && !FD_ISSET (fd, exceptfds)) - continue; - h = (HANDLE) _get_osfhandle (fd); - if (h == INVALID_HANDLE_VALUE) - { - /* If the underlying handle is INVALID_HANDLE_VALUE, then - this descriptor is no more. */ - if (FD_ISSET (fd, exceptfds)) - ++num_ready; - continue; - } - /* The only exceptional condition we recognize is a closed file - descriptor. Since we have already checked for that - condition, clear the exceptional bit for this descriptor. */ - FD_CLR (fd, exceptfds); - if (FD_ISSET (fd, readfds)) - { - gdb_assert (num_handles < MAXIMUM_WAIT_OBJECTS); - handles[num_handles++] = h; - } - } - /* If we don't need to wait for any handles, we are done. */ - if (!num_handles) - return num_ready; - event = WaitForMultipleObjects (num_handles, - handles, - FALSE, - timeout - ? (timeout->tv_sec * 1000 + timeout->tv_usec) - : INFINITE); - /* EVENT can only be a value in the WAIT_ABANDONED_0 range if the - HANDLES included an abandoned mutex. Since GDB doesn't use - mutexes, that should never occur. */ - gdb_assert (!(WAIT_ABANDONED_0 <= event - && event < WAIT_ABANDONED_0 + num_handles)); - if (event == WAIT_FAILED) - return -1; - if (event == WAIT_TIMEOUT) - return num_ready; - /* Run through the READFDS, clearing bits corresponding to descriptors - for which input is unavailable. */ - num_ready += num_handles; - h = handles[event - WAIT_OBJECT_0]; - for (fd = 0; fd < n; ++fd) - { - HANDLE fd_h; - if (!FD_ISSET (fd, readfds)) - continue; - fd_h = (HANDLE) _get_osfhandle (fd); - /* This handle might be ready, even though it wasn't the handle - returned by WaitForMultipleObjects. */ - if (fd_h != h && WaitForSingleObject (fd_h, 0) != WAIT_OBJECT_0) - { - FD_CLR (fd, readfds); - --num_ready; - } - } - - return num_ready; -#else - return select (n, readfds, writefds, exceptfds, timeout); -#endif -} - /* Called by gdb_do_one_event to wait for new events on the monitored file descriptors. Queue file events as they are detected by the poll. diff --git a/gdb/gdb_select.h b/gdb/gdb_select.h new file mode 100644 index 0000000000..1054d6e986 --- /dev/null +++ b/gdb/gdb_select.h @@ -0,0 +1,37 @@ +/* Slightly more portable version of . + + Copyright (C) 2006 + Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. */ + +#if !defined(GDB_SELECT_H) +#define GDB_SELECT_H + +#ifdef HAVE_SYS_SELECT_H +#include +#endif + +#ifdef USE_WIN32API +#include +#endif + +extern int gdb_select (int n, fd_set *readfds, fd_set *writefds, + fd_set *exceptfds, struct timeval *timeout); + +#endif /* !defined(GDB_SELECT_H) */ diff --git a/gdb/inflow.c b/gdb/inflow.c index adfec1b326..83a0c9d828 100644 --- a/gdb/inflow.c +++ b/gdb/inflow.c @@ -1,6 +1,6 @@ /* Low level interface to ptrace, for GDB when running under Unix. Copyright (C) 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, - 1996, 1998, 1999, 2000, 2001, 2002, 2003, 2004 + 1996, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. This file is part of GDB. @@ -32,9 +32,7 @@ #include "gdb_string.h" #include #include -#ifdef HAVE_SYS_SELECT_H -#include -#endif +#include "gdb_select.h" #include "inflow.h" @@ -129,7 +127,6 @@ gdb_has_a_terminal (void) #endif gdb_has_a_terminal_flag = no; - stdin_serial = serial_fdopen (0); if (stdin_serial != NULL) { our_ttystate = serial_get_tty_state (stdin_serial); @@ -643,7 +640,7 @@ handle_sigio (int signo) FD_ZERO (&readfds); FD_SET (target_activity_fd, &readfds); - numfds = select (target_activity_fd + 1, &readfds, NULL, NULL, NULL); + numfds = gdb_select (target_activity_fd + 1, &readfds, NULL, NULL, NULL); if (numfds >= 0 && FD_ISSET (target_activity_fd, &readfds)) { #ifndef _WIN32 @@ -730,6 +727,18 @@ gdb_setpgid (void) return retval; } +/* Get all the current tty settings (including whether we have a + tty at all!). We can't do this in _initialize_inflow because + serial_fdopen() won't work until the serial_ops_list is + initialized, but we don't want to do it lazily either, so + that we can guarantee stdin_serial is opened if there is + a terminal. */ +void +initialize_stdin_serial (void) +{ + stdin_serial = serial_fdopen (0); +} + void _initialize_inflow (void) { diff --git a/gdb/mingw-hdep.c b/gdb/mingw-hdep.c index 1318cfdd38..79b23dc255 100644 --- a/gdb/mingw-hdep.c +++ b/gdb/mingw-hdep.c @@ -21,7 +21,10 @@ Boston, MA 02110-1301, USA. */ #include "defs.h" +#include "serial.h" +#include "gdb_assert.h" +#include "gdb_select.h" #include "gdb_string.h" #include @@ -69,3 +72,124 @@ safe_strerror (int errnum) return buffer; } + +/* Wrapper for select. On Windows systems, where the select interface + only works for sockets, this uses the GDB serial abstraction to + handle sockets, consoles, pipes, and serial ports. + + The arguments to this function are the same as the traditional + arguments to select on POSIX platforms. */ + +int +gdb_select (int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, + struct timeval *timeout) +{ + static HANDLE never_handle; + HANDLE handles[MAXIMUM_WAIT_OBJECTS]; + HANDLE h; + DWORD event; + DWORD num_handles; + int fd; + int num_ready; + int indx; + + num_ready = 0; + num_handles = 0; + for (fd = 0; fd < n; ++fd) + { + HANDLE read = NULL, except = NULL; + struct serial *scb; + + /* There is no support yet for WRITEFDS. At present, this isn't + used by GDB -- but we do not want to silently ignore WRITEFDS + if something starts using it. */ + gdb_assert (!writefds || !FD_ISSET (fd, writefds)); + + if (!FD_ISSET (fd, readfds) + && !FD_ISSET (fd, exceptfds)) + continue; + h = (HANDLE) _get_osfhandle (fd); + + scb = serial_for_fd (fd); + if (scb) + serial_wait_handle (scb, &read, &except); + + if (read == NULL) + read = h; + if (except == NULL) + { + if (!never_handle) + never_handle = CreateEvent (0, FALSE, FALSE, 0); + + except = never_handle; + } + + if (FD_ISSET (fd, readfds)) + { + gdb_assert (num_handles < MAXIMUM_WAIT_OBJECTS); + handles[num_handles++] = read; + } + + if (FD_ISSET (fd, exceptfds)) + { + gdb_assert (num_handles < MAXIMUM_WAIT_OBJECTS); + handles[num_handles++] = except; + } + } + /* If we don't need to wait for any handles, we are done. */ + if (!num_handles) + { + if (timeout) + Sleep (timeout->tv_sec * 1000 + timeout->tv_usec / 1000); + + return 0; + } + + event = WaitForMultipleObjects (num_handles, + handles, + FALSE, + timeout + ? (timeout->tv_sec * 1000 + + timeout->tv_usec / 1000) + : INFINITE); + /* EVENT can only be a value in the WAIT_ABANDONED_0 range if the + HANDLES included an abandoned mutex. Since GDB doesn't use + mutexes, that should never occur. */ + gdb_assert (!(WAIT_ABANDONED_0 <= event + && event < WAIT_ABANDONED_0 + num_handles)); + if (event == WAIT_FAILED) + return -1; + if (event == WAIT_TIMEOUT) + return 0; + /* Run through the READFDS, clearing bits corresponding to descriptors + for which input is unavailable. */ + h = handles[event - WAIT_OBJECT_0]; + for (fd = 0, indx = 0; fd < n; ++fd) + { + HANDLE fd_h; + + if (FD_ISSET (fd, readfds)) + { + fd_h = handles[indx++]; + /* This handle might be ready, even though it wasn't the handle + returned by WaitForMultipleObjects. */ + if (fd_h != h && WaitForSingleObject (fd_h, 0) != WAIT_OBJECT_0) + FD_CLR (fd, readfds); + else + num_ready++; + } + + if (FD_ISSET (fd, exceptfds)) + { + fd_h = handles[indx++]; + /* This handle might be ready, even though it wasn't the handle + returned by WaitForMultipleObjects. */ + if (fd_h != h && WaitForSingleObject (fd_h, 0) != WAIT_OBJECT_0) + FD_CLR (fd, exceptfds); + else + num_ready++; + } + } + + return num_ready; +} diff --git a/gdb/posix-hdep.c b/gdb/posix-hdep.c index ca405f985f..3ad6f922e8 100644 --- a/gdb/posix-hdep.c +++ b/gdb/posix-hdep.c @@ -24,6 +24,8 @@ #include "gdb_string.h" +#include "gdb_select.h" + /* The strerror() function can return NULL for errno values that are out of range. Provide a "safe" version that always returns a printable string. */ @@ -43,3 +45,11 @@ safe_strerror (int errnum) return (msg); } +/* Wrapper for select. Nothing special needed on POSIX platforms. */ + +int +gdb_select (int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, + struct timeval *timeout) +{ + return select (n, readfds, writefds, exceptfds, timeout); +} diff --git a/gdb/remote-st.c b/gdb/remote-st.c index 6d7ea19f51..c7c39a1450 100644 --- a/gdb/remote-st.c +++ b/gdb/remote-st.c @@ -704,7 +704,7 @@ connect_command (char *args, int fromtty) { FD_SET (0, &readfds); FD_SET (deprecated_serial_fd (st2000_desc), &readfds); - numfds = select (sizeof (readfds) * 8, &readfds, 0, 0, 0); + numfds = gdb_select (sizeof (readfds) * 8, &readfds, 0, 0, 0); } while (numfds == 0); diff --git a/gdb/ser-base.c b/gdb/ser-base.c index a43f08bb18..8b449cd0f9 100644 --- a/gdb/ser-base.c +++ b/gdb/ser-base.c @@ -1,7 +1,7 @@ /* Generic serial interface functions. Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, - 2003, 2004, 2005 Free Software Foundation, Inc. + 2003, 2004, 2005, 2006 Free Software Foundation, Inc. This file is part of GDB. @@ -25,6 +25,7 @@ #include "ser-base.h" #include "event-loop.h" +#include "gdb_select.h" #include "gdb_string.h" #include #ifdef USE_WIN32API @@ -202,9 +203,9 @@ ser_base_wait_for (struct serial *scb, int timeout) FD_SET (scb->fd, &exceptfds); if (timeout >= 0) - numfds = select (scb->fd + 1, &readfds, 0, &exceptfds, &tv); + numfds = gdb_select (scb->fd + 1, &readfds, 0, &exceptfds, &tv); else - numfds = select (scb->fd + 1, &readfds, 0, &exceptfds, 0); + numfds = gdb_select (scb->fd + 1, &readfds, 0, &exceptfds, 0); if (numfds <= 0) { diff --git a/gdb/ser-mingw.c b/gdb/ser-mingw.c new file mode 100644 index 0000000000..7a6f232379 --- /dev/null +++ b/gdb/ser-mingw.c @@ -0,0 +1,796 @@ +/* Serial interface for local (hardwired) serial ports on Windows systems + + Copyright (C) 2006 + Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. */ + +#include "defs.h" +#include "serial.h" +#include "ser-base.h" +#include "ser-tcp.h" + +#include + +#include +#include +#include + +#include "gdb_assert.h" +#include "gdb_string.h" + +void _initialize_ser_windows (void); + +struct ser_windows_state +{ + int in_progress; + OVERLAPPED ov; + DWORD lastCommMask; + HANDLE except_event; +}; + +/* Open up a real live device for serial I/O. */ + +static int +ser_windows_open (struct serial *scb, const char *name) +{ + HANDLE h; + struct ser_windows_state *state; + COMMTIMEOUTS timeouts; + + /* Only allow COM ports. */ + if (strncmp (name, "COM", 3) != 0) + { + errno = ENOENT; + return -1; + } + + h = CreateFile (name, GENERIC_READ | GENERIC_WRITE, 0, NULL, + OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL); + if (h == INVALID_HANDLE_VALUE) + { + errno = ENOENT; + return -1; + } + + scb->fd = _open_osfhandle ((long) h, O_RDWR); + if (scb->fd < 0) + { + errno = ENOENT; + return -1; + } + + if (!SetCommMask (h, EV_RXCHAR)) + { + errno = EINVAL; + return -1; + } + + timeouts.ReadIntervalTimeout = MAXDWORD; + timeouts.ReadTotalTimeoutConstant = 0; + timeouts.ReadTotalTimeoutMultiplier = 0; + timeouts.WriteTotalTimeoutConstant = 0; + timeouts.WriteTotalTimeoutMultiplier = 0; + if (!SetCommTimeouts (h, &timeouts)) + { + errno = EINVAL; + return -1; + } + + state = xmalloc (sizeof (struct ser_windows_state)); + memset (state, 0, sizeof (struct ser_windows_state)); + scb->state = state; + + /* Create a manual reset event to watch the input buffer. */ + state->ov.hEvent = CreateEvent (0, TRUE, FALSE, 0); + + /* Create a (currently unused) handle to record exceptions. */ + state->except_event = CreateEvent (0, TRUE, FALSE, 0); + + return 0; +} + +/* Wait for the output to drain away, as opposed to flushing (discarding) + it. */ + +static int +ser_windows_drain_output (struct serial *scb) +{ + HANDLE h = (HANDLE) _get_osfhandle (scb->fd); + + return (FlushFileBuffers (h) != 0) ? 0 : -1; +} + +static int +ser_windows_flush_output (struct serial *scb) +{ + HANDLE h = (HANDLE) _get_osfhandle (scb->fd); + + return (PurgeComm (h, PURGE_TXCLEAR) != 0) ? 0 : -1; +} + +static int +ser_windows_flush_input (struct serial *scb) +{ + HANDLE h = (HANDLE) _get_osfhandle (scb->fd); + + return (PurgeComm (h, PURGE_RXCLEAR) != 0) ? 0 : -1; +} + +static int +ser_windows_send_break (struct serial *scb) +{ + HANDLE h = (HANDLE) _get_osfhandle (scb->fd); + + if (SetCommBreak (h) == 0) + return -1; + + /* Delay for 250 milliseconds. */ + Sleep (250); + + if (ClearCommBreak (h)) + return -1; + + return 0; +} + +static void +ser_windows_raw (struct serial *scb) +{ + HANDLE h = (HANDLE) _get_osfhandle (scb->fd); + DCB state; + + if (GetCommState (h, &state) == 0) + return; + + state.fParity = FALSE; + state.fOutxCtsFlow = FALSE; + state.fOutxDsrFlow = FALSE; + state.fDtrControl = DTR_CONTROL_ENABLE; + state.fDsrSensitivity = FALSE; + state.fOutX = FALSE; + state.fInX = FALSE; + state.fNull = FALSE; + state.fAbortOnError = FALSE; + state.ByteSize = 8; + state.Parity = NOPARITY; + + scb->current_timeout = 0; + + if (SetCommState (h, &state) == 0) + warning (_("SetCommState failed\n")); +} + +static int +ser_windows_setstopbits (struct serial *scb, int num) +{ + HANDLE h = (HANDLE) _get_osfhandle (scb->fd); + DCB state; + + if (GetCommState (h, &state) == 0) + return -1; + + switch (num) + { + case SERIAL_1_STOPBITS: + state.StopBits = ONESTOPBIT; + break; + case SERIAL_1_AND_A_HALF_STOPBITS: + state.StopBits = ONE5STOPBITS; + break; + case SERIAL_2_STOPBITS: + state.StopBits = TWOSTOPBITS; + break; + default: + return 1; + } + + return (SetCommState (h, &state) != 0) ? 0 : -1; +} + +static int +ser_windows_setbaudrate (struct serial *scb, int rate) +{ + HANDLE h = (HANDLE) _get_osfhandle (scb->fd); + DCB state; + + if (GetCommState (h, &state) == 0) + return -1; + + state.BaudRate = rate; + + return (SetCommState (h, &state) != 0) ? 0 : -1; +} + +static void +ser_windows_close (struct serial *scb) +{ + struct ser_windows_state *state; + + /* Stop any pending selects. */ + CancelIo ((HANDLE) _get_osfhandle (scb->fd)); + state = scb->state; + CloseHandle (state->ov.hEvent); + CloseHandle (state->except_event); + + if (scb->fd < 0) + return; + + close (scb->fd); + scb->fd = -1; + + xfree (scb->state); +} + +static void +ser_windows_wait_handle (struct serial *scb, HANDLE *read, HANDLE *except) +{ + struct ser_windows_state *state; + COMSTAT status; + DWORD errors; + HANDLE h = (HANDLE) _get_osfhandle (scb->fd); + + state = scb->state; + + *except = state->except_event; + *read = state->ov.hEvent; + + if (state->in_progress) + return; + + /* Reset the mask - we are only interested in any characters which + arrive after this point, not characters which might have arrived + and already been read. */ + + /* This really, really shouldn't be necessary - just the second one. + But otherwise an internal flag for EV_RXCHAR does not get + cleared, and we get a duplicated event, if the last batch + of characters included at least two arriving close together. */ + if (!SetCommMask (h, 0)) + warning (_("ser_windows_wait_handle: reseting mask failed")); + + if (!SetCommMask (h, EV_RXCHAR)) + warning (_("ser_windows_wait_handle: reseting mask failed (2)")); + + /* There's a potential race condition here; we must check cbInQue + and not wait if that's nonzero. */ + + ClearCommError (h, &errors, &status); + if (status.cbInQue > 0) + { + SetEvent (state->ov.hEvent); + return; + } + + state->in_progress = 1; + ResetEvent (state->ov.hEvent); + state->lastCommMask = -2; + if (WaitCommEvent (h, &state->lastCommMask, &state->ov)) + { + gdb_assert (state->lastCommMask & EV_RXCHAR); + SetEvent (state->ov.hEvent); + } + else + gdb_assert (GetLastError () == ERROR_IO_PENDING); +} + +static int +ser_windows_read_prim (struct serial *scb, size_t count) +{ + struct ser_windows_state *state; + OVERLAPPED ov; + DWORD bytes_read, bytes_read_tmp; + HANDLE h; + gdb_byte *p; + + state = scb->state; + if (state->in_progress) + { + WaitForSingleObject (state->ov.hEvent, INFINITE); + state->in_progress = 0; + ResetEvent (state->ov.hEvent); + } + + memset (&ov, 0, sizeof (OVERLAPPED)); + ov.hEvent = CreateEvent (0, FALSE, FALSE, 0); + h = (HANDLE) _get_osfhandle (scb->fd); + + if (!ReadFile (h, scb->buf, /* count */ 1, &bytes_read, &ov)) + { + if (GetLastError () != ERROR_IO_PENDING + || !GetOverlappedResult (h, &ov, &bytes_read, TRUE)) + bytes_read = -1; + } + + CloseHandle (ov.hEvent); + return bytes_read; +} + +static int +ser_windows_write_prim (struct serial *scb, const void *buf, size_t len) +{ + struct ser_windows_state *state; + OVERLAPPED ov; + DWORD bytes_written; + HANDLE h; + + memset (&ov, 0, sizeof (OVERLAPPED)); + ov.hEvent = CreateEvent (0, FALSE, FALSE, 0); + h = (HANDLE) _get_osfhandle (scb->fd); + if (!WriteFile (h, buf, len, &bytes_written, &ov)) + { + if (GetLastError () != ERROR_IO_PENDING + || !GetOverlappedResult (h, &ov, &bytes_written, TRUE)) + bytes_written = -1; + } + + CloseHandle (ov.hEvent); + return bytes_written; +} + +struct ser_console_state +{ + HANDLE read_event; + HANDLE except_event; + + HANDLE start_select; + HANDLE stop_select; +}; + +static DWORD WINAPI +console_select_thread (void *arg) +{ + struct serial *scb = arg; + struct ser_console_state *state, state_copy; + int event_index, fd; + HANDLE h; + + /* Copy useful information out of the control block, to make sure + that we do not race with freeing it. */ + state_copy = *(struct ser_console_state *) scb->state; + state = &state_copy; + fd = scb->fd; + + h = (HANDLE) _get_osfhandle (fd); + + while (1) + { + HANDLE wait_events[2]; + INPUT_RECORD record; + DWORD n_records; + + wait_events[0] = state->start_select; + wait_events[1] = state->stop_select; + + if (WaitForMultipleObjects (2, wait_events, FALSE, INFINITE) != WAIT_OBJECT_0) + { + CloseHandle (state->stop_select); + return 0; + } + + retry: + wait_events[0] = state->stop_select; + wait_events[1] = h; + + event_index = WaitForMultipleObjects (2, wait_events, FALSE, INFINITE); + + if (event_index == WAIT_OBJECT_0 + || WaitForSingleObject (state->stop_select, 0) == WAIT_OBJECT_0) + { + CloseHandle (state->stop_select); + return 0; + } + + if (event_index != WAIT_OBJECT_0 + 1) + { + /* Wait must have failed; assume an error has occured, e.g. + the handle has been closed. */ + SetEvent (state->except_event); + continue; + } + + /* We've got a pending event on the console. See if it's + of interest. */ + if (!PeekConsoleInput (h, &record, 1, &n_records) || n_records != 1) + { + /* Something went wrong. Maybe the console is gone. */ + SetEvent (state->except_event); + continue; + } + + if (record.EventType == KEY_EVENT && record.Event.KeyEvent.bKeyDown) + { + /* This is really a keypress. */ + SetEvent (state->read_event); + continue; + } + + /* Otherwise discard it and wait again. */ + ReadConsoleInput (h, &record, 1, &n_records); + goto retry; + } +} + +static int +fd_is_pipe (int fd) +{ + if (PeekNamedPipe ((HANDLE) _get_osfhandle (fd), NULL, 0, NULL, NULL, NULL)) + return 1; + else + return 0; +} + +static DWORD WINAPI +pipe_select_thread (void *arg) +{ + struct serial *scb = arg; + struct ser_console_state *state, state_copy; + int event_index, fd; + HANDLE h; + + /* Copy useful information out of the control block, to make sure + that we do not race with freeing it. */ + state_copy = *(struct ser_console_state *) scb->state; + state = &state_copy; + fd = scb->fd; + + h = (HANDLE) _get_osfhandle (fd); + + while (1) + { + HANDLE wait_events[2]; + DWORD n_avail; + + wait_events[0] = state->start_select; + wait_events[1] = state->stop_select; + + if (WaitForMultipleObjects (2, wait_events, FALSE, INFINITE) != WAIT_OBJECT_0) + { + CloseHandle (state->stop_select); + return 0; + } + + retry: + if (!PeekNamedPipe (h, NULL, 0, NULL, &n_avail, NULL)) + { + SetEvent (state->except_event); + continue; + } + + if (n_avail > 0) + { + SetEvent (state->read_event); + continue; + } + + if (WaitForSingleObject (state->stop_select, 0) == WAIT_OBJECT_0) + { + CloseHandle (state->stop_select); + return 0; + } + + Sleep (10); + goto retry; + } +} + +static void +ser_console_wait_handle (struct serial *scb, HANDLE *read, HANDLE *except) +{ + struct ser_console_state *state = scb->state; + + if (state == NULL) + { + DWORD threadId; + int is_tty; + + is_tty = isatty (scb->fd); + if (!is_tty && !fd_is_pipe (scb->fd)) + { + *read = NULL; + *except = NULL; + return; + } + + state = xmalloc (sizeof (struct ser_console_state)); + memset (state, 0, sizeof (struct ser_console_state)); + scb->state = state; + + /* Create auto reset events to wake and terminate the select thread. */ + state->start_select = CreateEvent (0, FALSE, FALSE, 0); + state->stop_select = CreateEvent (0, FALSE, FALSE, 0); + + /* Create our own events to report read and exceptions separately. + The exception event is currently never used. */ + state->read_event = CreateEvent (0, FALSE, FALSE, 0); + state->except_event = CreateEvent (0, FALSE, FALSE, 0); + + /* And finally start the select thread. */ + if (is_tty) + CreateThread (NULL, 0, console_select_thread, scb, 0, &threadId); + else + CreateThread (NULL, 0, pipe_select_thread, scb, 0, &threadId); + } + + ResetEvent (state->read_event); + ResetEvent (state->except_event); + + SetEvent (state->start_select); + + *read = state->read_event; + *except = state->except_event; +} + +static void +ser_console_close (struct serial *scb) +{ + struct ser_console_state *state = scb->state; + + if (scb->state) + { + SetEvent (state->stop_select); + + CloseHandle (state->read_event); + CloseHandle (state->except_event); + + xfree (scb->state); + } +} + +struct ser_console_ttystate +{ + int is_a_tty; +}; + +static serial_ttystate +ser_console_get_tty_state (struct serial *scb) +{ + if (isatty (scb->fd)) + { + struct ser_console_ttystate *state; + state = (struct ser_console_ttystate *) xmalloc (sizeof *state); + state->is_a_tty = 1; + return state; + } + else + return NULL; +} + +struct net_windows_state +{ + HANDLE read_event; + HANDLE except_event; + + HANDLE start_select; + HANDLE stop_select; + HANDLE sock_event; +}; + +static DWORD WINAPI +net_windows_select_thread (void *arg) +{ + struct serial *scb = arg; + struct net_windows_state *state, state_copy; + int event_index, fd; + + /* Copy useful information out of the control block, to make sure + that we do not race with freeing it. */ + state_copy = *(struct net_windows_state *) scb->state; + state = &state_copy; + fd = scb->fd; + + while (1) + { + HANDLE wait_events[2]; + WSANETWORKEVENTS events; + + wait_events[0] = state->start_select; + wait_events[1] = state->stop_select; + + if (WaitForMultipleObjects (2, wait_events, FALSE, INFINITE) != WAIT_OBJECT_0) + { + CloseHandle (state->stop_select); + return 0; + } + + wait_events[0] = state->stop_select; + wait_events[1] = state->sock_event; + + event_index = WaitForMultipleObjects (2, wait_events, FALSE, INFINITE); + + if (event_index == WAIT_OBJECT_0 + || WaitForSingleObject (state->stop_select, 0) == WAIT_OBJECT_0) + { + CloseHandle (state->stop_select); + return 0; + } + + if (event_index != WAIT_OBJECT_0 + 1) + { + /* Some error has occured. Assume that this is an error + condition. */ + SetEvent (state->except_event); + continue; + } + + /* Enumerate the internal network events, and reset the object that + signalled us to catch the next event. */ + WSAEnumNetworkEvents (fd, state->sock_event, &events); + + if (events.lNetworkEvents & FD_READ) + SetEvent (state->read_event); + + if (events.lNetworkEvents & FD_CLOSE) + SetEvent (state->except_event); + } +} + +static void +net_windows_wait_handle (struct serial *scb, HANDLE *read, HANDLE *except) +{ + struct net_windows_state *state = scb->state; + + ResetEvent (state->read_event); + ResetEvent (state->except_event); + + SetEvent (state->start_select); + + *read = state->read_event; + *except = state->except_event; +} + +static int +net_windows_open (struct serial *scb, const char *name) +{ + struct net_windows_state *state; + int ret; + DWORD threadId; + + ret = net_open (scb, name); + if (ret != 0) + return ret; + + state = xmalloc (sizeof (struct net_windows_state)); + memset (state, 0, sizeof (struct net_windows_state)); + scb->state = state; + + /* Create auto reset events to wake and terminate the select thread. */ + state->start_select = CreateEvent (0, FALSE, FALSE, 0); + state->stop_select = CreateEvent (0, FALSE, FALSE, 0); + + /* Associate an event with the socket. */ + state->sock_event = CreateEvent (0, TRUE, FALSE, 0); + WSAEventSelect (scb->fd, state->sock_event, FD_READ | FD_CLOSE); + + /* Create our own events to report read and close separately. */ + state->read_event = CreateEvent (0, FALSE, FALSE, 0); + state->except_event = CreateEvent (0, FALSE, FALSE, 0); + + /* And finally start the select thread. */ + CreateThread (NULL, 0, net_windows_select_thread, scb, 0, &threadId); + + return 0; +} + + +static void +net_windows_close (struct serial *scb) +{ + struct net_windows_state *state = scb->state; + + SetEvent (state->stop_select); + + CloseHandle (state->read_event); + CloseHandle (state->except_event); + CloseHandle (state->start_select); + CloseHandle (state->sock_event); + + xfree (scb->state); + + net_close (scb); +} + +void +_initialize_ser_windows (void) +{ + WSADATA wsa_data; + struct serial_ops *ops; + + /* First register the serial port driver. */ + + ops = XMALLOC (struct serial_ops); + memset (ops, 0, sizeof (struct serial_ops)); + ops->name = "hardwire"; + ops->next = 0; + ops->open = ser_windows_open; + ops->close = ser_windows_close; + + ops->flush_output = ser_windows_flush_output; + ops->flush_input = ser_windows_flush_input; + ops->send_break = ser_windows_send_break; + + /* These are only used for stdin; we do not need them for serial + ports, so supply the standard dummies. */ + ops->get_tty_state = ser_base_get_tty_state; + ops->set_tty_state = ser_base_set_tty_state; + ops->print_tty_state = ser_base_print_tty_state; + ops->noflush_set_tty_state = ser_base_noflush_set_tty_state; + + ops->go_raw = ser_windows_raw; + ops->setbaudrate = ser_windows_setbaudrate; + ops->setstopbits = ser_windows_setstopbits; + ops->drain_output = ser_windows_drain_output; + ops->readchar = ser_base_readchar; + ops->write = ser_base_write; + ops->async = ser_base_async; + ops->read_prim = ser_windows_read_prim; + ops->write_prim = ser_windows_write_prim; + ops->wait_handle = ser_windows_wait_handle; + + serial_add_interface (ops); + + /* Next create the dummy serial driver used for terminals. We only + provide the TTY-related methods. */ + + ops = XMALLOC (struct serial_ops); + memset (ops, 0, sizeof (struct serial_ops)); + + ops->name = "terminal"; + ops->next = 0; + + ops->close = ser_console_close; + ops->get_tty_state = ser_console_get_tty_state; + ops->set_tty_state = ser_base_set_tty_state; + ops->print_tty_state = ser_base_print_tty_state; + ops->noflush_set_tty_state = ser_base_noflush_set_tty_state; + ops->drain_output = ser_base_drain_output; + ops->wait_handle = ser_console_wait_handle; + + serial_add_interface (ops); + + /* If WinSock works, register the TCP/UDP socket driver. */ + + if (WSAStartup (MAKEWORD (1, 0), &wsa_data) != 0) + /* WinSock is unavailable. */ + return; + + ops = XMALLOC (struct serial_ops); + memset (ops, 0, sizeof (struct serial_ops)); + ops->name = "tcp"; + ops->next = 0; + ops->open = net_windows_open; + ops->close = net_windows_close; + ops->readchar = ser_base_readchar; + ops->write = ser_base_write; + ops->flush_output = ser_base_flush_output; + ops->flush_input = ser_base_flush_input; + ops->send_break = ser_base_send_break; + ops->go_raw = ser_base_raw; + ops->get_tty_state = ser_base_get_tty_state; + ops->set_tty_state = ser_base_set_tty_state; + ops->print_tty_state = ser_base_print_tty_state; + ops->noflush_set_tty_state = ser_base_noflush_set_tty_state; + ops->setbaudrate = ser_base_setbaudrate; + ops->setstopbits = ser_base_setstopbits; + ops->drain_output = ser_base_drain_output; + ops->async = ser_base_async; + ops->read_prim = net_read_prim; + ops->write_prim = net_write_prim; + ops->wait_handle = net_windows_wait_handle; + serial_add_interface (ops); +} diff --git a/gdb/ser-tcp.c b/gdb/ser-tcp.c index aed91c2765..bd104aa8f1 100644 --- a/gdb/ser-tcp.c +++ b/gdb/ser-tcp.c @@ -1,6 +1,6 @@ /* Serial interface for raw TCP connections on Un*x like systems. - Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2001, 2005 + Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2001, 2005, 2006 Free Software Foundation, Inc. This file is part of GDB. @@ -23,7 +23,7 @@ #include "defs.h" #include "serial.h" #include "ser-base.h" -#include "ser-unix.h" +#include "ser-tcp.h" #include @@ -56,8 +56,6 @@ typedef int socklen_t; #endif -static int net_open (struct serial *scb, const char *name); -static void net_close (struct serial *scb); void _initialize_ser_tcp (void); /* seconds to wait for connect */ @@ -67,7 +65,7 @@ void _initialize_ser_tcp (void); /* Open a tcp socket */ -static int +int net_open (struct serial *scb, const char *name) { char *port_str, hostname[100]; @@ -153,7 +151,7 @@ net_open (struct serial *scb, const char *name) { /* looks like we need to wait for the connect */ struct timeval t; - fd_set rset, wset; + fd_set rset, wset, eset; int polls = 0; FD_ZERO (&rset); @@ -174,10 +172,19 @@ net_open (struct serial *scb, const char *name) FD_SET (scb->fd, &rset); wset = rset; + eset = rset; t.tv_sec = 0; t.tv_usec = 1000000 / POLL_INTERVAL; - n = select (scb->fd + 1, &rset, &wset, NULL, &t); + /* POSIX systems return connection success or failure by signalling + wset. Windows systems return success in wset and failure in + eset. + + We must call select here, rather than gdb_select, because + the serial structure has not yet been initialized - the + MinGW select wrapper will not know that this FD refers + to a socket. */ + n = select (scb->fd + 1, &rset, &wset, &eset, &t); polls++; } while (n == 0 && polls <= TIMEOUT * POLL_INTERVAL); @@ -194,7 +201,7 @@ net_open (struct serial *scb, const char *name) { int res, err; socklen_t len; - len = sizeof(err); + len = sizeof (err); /* On Windows, the fourth parameter to getsockopt is a "char *"; on UNIX systems it is generally "void *". The cast to "void *" is OK everywhere, since in C "void *" can be implicitly @@ -230,7 +237,7 @@ net_open (struct serial *scb, const char *name) return 0; } -static void +void net_close (struct serial *scb) { if (scb->fd < 0) @@ -240,13 +247,13 @@ net_close (struct serial *scb) scb->fd = -1; } -static int +int net_read_prim (struct serial *scb, size_t count) { return recv (scb->fd, scb->buf, count, 0); } -static int +int net_write_prim (struct serial *scb, const void *buf, size_t count) { return send (scb->fd, buf, count, 0); @@ -255,13 +262,12 @@ net_write_prim (struct serial *scb, const void *buf, size_t count) void _initialize_ser_tcp (void) { - struct serial_ops *ops; #ifdef USE_WIN32API - WSADATA wsa_data; - if (WSAStartup (MAKEWORD (1, 0), &wsa_data) != 0) - /* WinSock is unavailable. */ - return; -#endif + /* Do nothing; the TCP serial operations will be initialized in + ser-mingw.c. */ + return; +#else + struct serial_ops *ops; ops = XMALLOC (struct serial_ops); memset (ops, 0, sizeof (struct serial_ops)); ops->name = "tcp"; @@ -285,4 +291,5 @@ _initialize_ser_tcp (void) ops->read_prim = net_read_prim; ops->write_prim = net_write_prim; serial_add_interface (ops); +#endif /* USE_WIN32API */ } diff --git a/gdb/ser-tcp.h b/gdb/ser-tcp.h new file mode 100644 index 0000000000..accaac76ce --- /dev/null +++ b/gdb/ser-tcp.h @@ -0,0 +1,32 @@ +/* Serial interface for raw TCP connections on Un*x like systems. + + Copyright (C) 2006 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. */ + +#ifndef SER_TCP_H +#define SER_TCP_H + +struct serial; + +extern int net_open (struct serial *scb, const char *name); +extern void net_close (struct serial *scb); +extern int net_read_prim (struct serial *scb, size_t count); +extern int net_write_prim (struct serial *scb, const void *buf, size_t count); + +#endif diff --git a/gdb/ser-unix.c b/gdb/ser-unix.c index 4a40c36662..7c10815a4e 100644 --- a/gdb/ser-unix.c +++ b/gdb/ser-unix.c @@ -31,6 +31,7 @@ #include #include +#include "gdb_select.h" #include "gdb_string.h" #ifdef HAVE_TERMIOS @@ -365,7 +366,7 @@ hardwire_send_break (struct serial *scb) the full length of time. I think that is OK. */ timeout.tv_sec = 0; timeout.tv_usec = 250000; - select (0, 0, 0, 0, &timeout); + gdb_select (0, 0, 0, 0, &timeout); status = ioctl (scb->fd, TIOCCBRK, 0); return status; } @@ -448,9 +449,9 @@ wait_for (struct serial *scb, int timeout) FD_SET (scb->fd, &readfds); if (timeout >= 0) - numfds = select (scb->fd + 1, &readfds, 0, 0, &tv); + numfds = gdb_select (scb->fd + 1, &readfds, 0, 0, &tv); else - numfds = select (scb->fd + 1, &readfds, 0, 0, 0); + numfds = gdb_select (scb->fd + 1, &readfds, 0, 0, 0); if (numfds <= 0) if (numfds == 0) diff --git a/gdb/serial.c b/gdb/serial.c index e5cf1b9d50..9ee2fa0ee3 100644 --- a/gdb/serial.c +++ b/gdb/serial.c @@ -1,7 +1,7 @@ /* Generic serial interface routines Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, - 2001, 2002 Free Software Foundation, Inc. + 2001, 2002, 2004, 2005, 2006 Free Software Foundation, Inc. This file is part of GDB. @@ -233,6 +233,22 @@ serial_open (const char *name) return scb; } +/* Return the open serial device for FD, if found, or NULL if FD + is not already opened. */ + +struct serial * +serial_for_fd (int fd) +{ + struct serial *scb; + struct serial_ops *ops; + + for (scb = scb_base; scb; scb = scb->next) + if (scb->fd == fd) + return scb; + + return NULL; +} + struct serial * serial_fdopen (const int fd) { @@ -246,12 +262,14 @@ serial_fdopen (const int fd) return scb; } - ops = serial_interface_lookup ("hardwire"); + ops = serial_interface_lookup ("terminal"); + if (!ops) + ops = serial_interface_lookup ("hardwire"); if (!ops) return NULL; - scb = XMALLOC (struct serial); + scb = XCALLOC (1, struct serial); scb->ops = ops; @@ -524,6 +542,19 @@ serial_debug_p (struct serial *scb) return scb->debug_p || global_serial_debug_p; } +#ifdef USE_WIN32API +void +serial_wait_handle (struct serial *scb, HANDLE *read, HANDLE *except) +{ + if (scb->ops->wait_handle) + scb->ops->wait_handle (scb, read, except); + else + { + *read = (HANDLE) _get_osfhandle (scb->fd); + *except = NULL; + } +} +#endif #if 0 /* The connect command is #if 0 because I hadn't thought of an elegant diff --git a/gdb/serial.h b/gdb/serial.h index a948ae1fac..d9a395b3fc 100644 --- a/gdb/serial.h +++ b/gdb/serial.h @@ -1,5 +1,6 @@ /* Remote serial support interface definitions for GDB, the GNU Debugger. - Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000 + Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, + 2004, 2005, 2006 Free Software Foundation, Inc. This file is part of GDB. @@ -22,6 +23,10 @@ #ifndef SERIAL_H #define SERIAL_H +#ifdef USE_WIN32API +#include +#endif + struct ui_file; /* For most routines, if a failure is indicated, then errno should be @@ -41,6 +46,10 @@ struct serial; extern struct serial *serial_open (const char *name); +/* Find an already opened serial stream using a file handle. */ + +extern struct serial *serial_for_fd (int fd); + /* Open a new serial stream using a file handle. */ extern struct serial *serial_fdopen (const int fd); @@ -238,6 +247,13 @@ struct serial_ops /* Perform a low-level write operation, writing (at most) COUNT bytes from BUF. */ int (*write_prim)(struct serial *scb, const void *buf, size_t count); + +#ifdef USE_WIN32API + /* Return a handle to wait on, indicating available data from SCB + when signaled, in *READ. Return a handle indicating errors + in *EXCEPT. */ + void (*wait_handle) (struct serial *scb, HANDLE *read, HANDLE *except); +#endif /* USE_WIN32API */ }; /* Add a new serial interface to the interface list */ @@ -248,4 +264,12 @@ extern void serial_add_interface (struct serial_ops * optable); extern void serial_log_command (const char *); +#ifdef USE_WIN32API + +/* Windows-only: find or create handles that we can wait on for this + serial device. */ +extern void serial_wait_handle (struct serial *, HANDLE *, HANDLE *); + +#endif /* USE_WIN32API */ + #endif /* SERIAL_H */ diff --git a/gdb/terminal.h b/gdb/terminal.h index 1b88542d55..19b297a65b 100644 --- a/gdb/terminal.h +++ b/gdb/terminal.h @@ -1,5 +1,6 @@ /* Terminal interface definitions for GDB, the GNU Debugger. - Copyright (C) 1986, 1989, 1990, 1991, 1992, 1993, 1995, 1996, 1999, 2000 + Copyright (C) 1986, 1989, 1990, 1991, 1992, 1993, 1995, 1996, 1999, 2000, + 2006 Free Software Foundation, Inc. This file is part of GDB. @@ -88,4 +89,7 @@ extern int job_control; we lack job control. */ extern int gdb_setpgid (void); +/* Set up a serial structure describing standard input. In inflow.c. */ +extern void initialize_stdin_serial (void); + #endif /* !defined (TERMINAL_H) */ diff --git a/gdb/top.c b/gdb/top.c index a5ee333f42..61968afb63 100644 --- a/gdb/top.c +++ b/gdb/top.c @@ -1550,6 +1550,8 @@ gdb_init (char *argv0) init_cli_cmds(); init_main (); /* But that omits this file! Do it now */ + initialize_stdin_serial (); + async_init_signals (); /* We need a default language for parsing expressions, so simple things like -- 2.34.1