mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2025-02-17 13:10:12 +08:00
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:
parent
a2e0acea42
commit
d69939bded
40
gdb/remote.c
40
gdb/remote.c
@ -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. */
|
||||
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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. */
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
12
gdb/serial.h
12
gdb/serial.h
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user