Change serial_send_break and serial_write to throw

This changes serial_send_break and serial_write to throw exceptions
rather than attempt to set errno and return an error indicator.  This
lets us correctly report failures on Windows.

Both functions had to be converted in a single patch because one
implementation of send_break works via write.

This also introduces remote_serial_send_break to handle error checking
when attempting to send a break.  This was previously ignored.

Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=30770
This commit is contained in:
Tom Tromey 2023-09-06 08:33:46 -06:00
parent a2e0acea42
commit d69939bded
10 changed files with 75 additions and 43 deletions

View File

@ -1264,6 +1264,7 @@ class remote_target : public process_stratum_target
int readchar (int timeout);
void remote_serial_write (const char *str, int len);
void remote_serial_send_break ();
int putpkt (const char *buf);
int putpkt_binary (const char *buf, int cnt);
@ -4623,15 +4624,13 @@ remote_target::get_offsets ()
void
remote_target::send_interrupt_sequence ()
{
struct remote_state *rs = get_remote_state ();
if (interrupt_sequence_mode == interrupt_sequence_control_c)
remote_serial_write ("\x03", 1);
else if (interrupt_sequence_mode == interrupt_sequence_break)
serial_send_break (rs->remote_desc);
remote_serial_send_break ();
else if (interrupt_sequence_mode == interrupt_sequence_break_g)
{
serial_send_break (rs->remote_desc);
remote_serial_send_break ();
remote_serial_write ("g", 1);
}
else
@ -4639,7 +4638,6 @@ remote_target::send_interrupt_sequence ()
interrupt_sequence_mode);
}
/* If STOP_REPLY is a T stop reply, look for the "thread" register,
and extract the PTID. Returns NULL_PTID if not found. */
@ -9859,16 +9857,42 @@ remote_target::remote_serial_write (const char *str, int len)
rs->got_ctrlc_during_io = 0;
if (serial_write (rs->remote_desc, str, len))
try
{
unpush_and_perror (this, _("Remote communication error. "
"Target disconnected"));
serial_write (rs->remote_desc, str, len);
}
catch (const gdb_exception_error &ex)
{
remote_unpush_target (this);
throw_error (TARGET_CLOSE_ERROR,
_("Remote communication error. "
"Target disconnected: %s"),
ex.what ());
}
if (rs->got_ctrlc_during_io)
set_quit_flag ();
}
void
remote_target::remote_serial_send_break ()
{
struct remote_state *rs = get_remote_state ();
try
{
serial_send_break (rs->remote_desc);
}
catch (const gdb_exception_error &ex)
{
remote_unpush_target (this);
throw_error (TARGET_CLOSE_ERROR,
_("Remote communication error. "
"Target disconnected: %s"),
ex.what ());
}
}
/* Return a string representing an escaped version of BUF, of len N.
E.g. \n is converted to \\n, \t to \\t, etc. */

View File

@ -471,7 +471,7 @@ ser_base_readchar (struct serial *scb, int timeout)
return generic_readchar (scb, timeout, do_ser_base_readchar);
}
int
void
ser_base_write (struct serial *scb, const void *buf, size_t count)
{
const char *str = (const char *) buf;
@ -487,12 +487,11 @@ ser_base_write (struct serial *scb, const void *buf, size_t count)
{
if (errno == EINTR)
continue;
return 1;
perror_with_name ("error while writing");
}
count -= cc;
str += cc;
}
return 0;
}
int
@ -514,10 +513,9 @@ ser_base_flush_input (struct serial *scb)
return SERIAL_ERROR;
}
int
void
ser_base_send_break (struct serial *scb)
{
return 0;
}
int

View File

@ -30,7 +30,7 @@ extern int generic_readchar (struct serial *scb, int timeout,
int timeout));
extern int ser_base_flush_output (struct serial *scb);
extern int ser_base_flush_input (struct serial *scb);
extern int ser_base_send_break (struct serial *scb);
extern void ser_base_send_break (struct serial *scb);
extern void ser_base_raw (struct serial *scb);
extern serial_ttystate ser_base_get_tty_state (struct serial *scb);
extern serial_ttystate ser_base_copy_tty_state (struct serial *scb,
@ -45,7 +45,7 @@ extern int ser_base_setstopbits (struct serial *scb, int num);
extern int ser_base_setparity (struct serial *scb, int parity);
extern int ser_base_drain_output (struct serial *scb);
extern int ser_base_write (struct serial *scb, const void *buf, size_t count);
extern void ser_base_write (struct serial *scb, const void *buf, size_t count);
extern void ser_base_async (struct serial *scb, int async_p);
extern int ser_base_readchar (struct serial *scb, int timeout);

View File

@ -118,21 +118,21 @@ ser_windows_flush_input (struct serial *scb)
return (PurgeComm (h, PURGE_RXCLEAR) != 0) ? 0 : -1;
}
static int
static void
ser_windows_send_break (struct serial *scb)
{
HANDLE h = (HANDLE) _get_osfhandle (scb->fd);
if (SetCommBreak (h) == 0)
return -1;
throw_winerror_with_name ("error calling SetCommBreak",
GetLastError ());
/* Delay for 250 milliseconds. */
Sleep (250);
if (ClearCommBreak (h) == 0)
return -1;
return 0;
throw_winerror_with_name ("error calling ClearCommBreak",
GetLastError ());
}
static void
@ -354,7 +354,7 @@ ser_windows_write_prim (struct serial *scb, const void *buf, size_t len)
{
if (GetLastError () != ERROR_IO_PENDING
|| !GetOverlappedResult (h, &ov, &bytes_written, TRUE))
bytes_written = -1;
throw_winerror_with_name ("error while writing", GetLastError ());
}
CloseHandle (ov.hEvent);
@ -986,14 +986,14 @@ pipe_windows_write (struct serial *scb, const void *buf, size_t count)
int pipeline_in_fd = fileno (ps->input);
if (pipeline_in_fd < 0)
return -1;
error (_("could not find file number for pipe"));
pipeline_in = (HANDLE) _get_osfhandle (pipeline_in_fd);
if (pipeline_in == INVALID_HANDLE_VALUE)
return -1;
error (_("could not find handle for pipe"));
if (! WriteFile (pipeline_in, buf, count, &written, NULL))
return -1;
throw_winerror_with_name (_("could not write to pipe"), GetLastError ());
return written;
}

View File

@ -419,14 +419,17 @@ net_write_prim (struct serial *scb, const void *buf, size_t count)
UNIX systems it is generally "const void *". The cast to "const
char *" is OK everywhere, since in C++ any data pointer type can
be implicitly converted to "const void *". */
return send (scb->fd, (const char *) buf, count, 0);
int result = send (scb->fd, (const char *) buf, count, 0);
if (result == -1 && errno != EINTR)
perror_with_name ("error while writing");
return result;
}
int
void
ser_tcp_send_break (struct serial *scb)
{
/* Send telnet IAC and BREAK characters. */
return (serial_write (scb, "\377\363", 2));
serial_write (scb, "\377\363", 2);
}
#ifndef USE_WIN32API

View File

@ -26,6 +26,6 @@ extern void 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);
extern int ser_tcp_send_break (struct serial *scb);
extern void ser_tcp_send_break (struct serial *scb);
#endif

View File

@ -75,7 +75,10 @@ uds_read_prim (struct serial *scb, size_t count)
static int
uds_write_prim (struct serial *scb, const void *buf, size_t count)
{
return send (scb->fd, buf, count, 0);
int result = send (scb->fd, buf, count, 0);
if (result == -1 && errno != EINTR)
perror_with_name ("error while writing");
return result;
}
/* The local socket ops. */

View File

@ -66,7 +66,7 @@ static void hardwire_print_tty_state (struct serial *, serial_ttystate,
static int hardwire_drain_output (struct serial *);
static int hardwire_flush_output (struct serial *);
static int hardwire_flush_input (struct serial *);
static int hardwire_send_break (struct serial *);
static void hardwire_send_break (struct serial *);
static int hardwire_setstopbits (struct serial *, int);
/* Open up a real live device for serial I/O. */
@ -182,10 +182,11 @@ hardwire_flush_input (struct serial *scb)
return tcflush (scb->fd, TCIFLUSH);
}
static int
static void
hardwire_send_break (struct serial *scb)
{
return tcsendbreak (scb->fd, 0);
if (tcsendbreak (scb->fd, 0) == -1)
perror_with_name ("sending break");
}
static void
@ -579,5 +580,8 @@ ser_unix_read_prim (struct serial *scb, size_t count)
int
ser_unix_write_prim (struct serial *scb, const void *buf, size_t len)
{
return write (scb->fd, buf, len);
int result = write (scb->fd, buf, len);
if (result == -1 && errno != EINTR)
perror_with_name ("error while writing");
return result;
}

View File

@ -399,7 +399,7 @@ serial_readchar (struct serial *scb, int timeout)
return (ch);
}
int
void
serial_write (struct serial *scb, const void *buf, size_t count)
{
if (serial_logfp != NULL)
@ -428,7 +428,7 @@ serial_write (struct serial *scb, const void *buf, size_t count)
gdb_flush (gdb_stdlog);
}
return (scb->ops->write (scb, buf, count));
scb->ops->write (scb, buf, count);
}
void
@ -461,13 +461,13 @@ serial_flush_input (struct serial *scb)
return scb->ops->flush_input (scb);
}
int
void
serial_send_break (struct serial *scb)
{
if (serial_logfp != NULL)
serial_logchar (serial_logfp, 'w', SERIAL_BREAK, 0);
return (scb->ops->send_break (scb));
scb->ops->send_break (scb);
}
void

View File

@ -119,10 +119,10 @@ enum serial_rc {
extern int serial_readchar (struct serial *scb, int timeout);
/* Write COUNT bytes from BUF to the port SCB. Returns 0 for
success, non-zero for failure. */
/* Write COUNT bytes from BUF to the port SCB. Throws exception on
error. */
extern int serial_write (struct serial *scb, const void *buf, size_t count);
extern void serial_write (struct serial *scb, const void *buf, size_t count);
/* Write a printf style string onto the serial port. */
@ -145,7 +145,7 @@ extern int serial_flush_input (struct serial *);
/* Send a break between 0.25 and 0.5 seconds long. */
extern int serial_send_break (struct serial *scb);
extern void serial_send_break (struct serial *scb);
/* Turn the port into raw mode. */
@ -263,12 +263,12 @@ struct serial_ops
void (*close) (struct serial *);
int (*fdopen) (struct serial *, int fd);
int (*readchar) (struct serial *, int timeout);
int (*write) (struct serial *, const void *buf, size_t count);
void (*write) (struct serial *, const void *buf, size_t count);
/* Discard pending output */
int (*flush_output) (struct serial *);
/* Discard pending input */
int (*flush_input) (struct serial *);
int (*send_break) (struct serial *);
void (*send_break) (struct serial *);
void (*go_raw) (struct serial *);
serial_ttystate (*get_tty_state) (struct serial *);
serial_ttystate (*copy_tty_state) (struct serial *, serial_ttystate);