blob: 9a961f47d189bdbd43087092759fb425e10fadbd [file] [log] [blame]
/* Remote File-I/O communications
Copyright (C) 2003, 2005, 2006, 2007, 2008 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 3 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, see <http://www.gnu.org/licenses/>. */
/* See the GDB User Guide for details of the GDB remote protocol. */
#include "defs.h"
#include "gdb_string.h"
#include "gdbcmd.h"
#include "remote.h"
#include "gdb/fileio.h"
#include "exceptions.h"
#include "remote-fileio.h"
#include "target-fileio.h"
#include <signal.h>
static int remote_fio_ctrl_c_flag = 0;
#if defined (HAVE_SIGACTION) && defined (SA_RESTART)
static struct sigaction remote_fio_sa;
static struct sigaction remote_fio_osa;
#else
static void (*remote_fio_ofunc)(int);
#endif
static void
remote_fileio_sig_init (void)
{
#if defined (HAVE_SIGACTION) && defined (SA_RESTART)
remote_fio_sa.sa_handler = SIG_IGN;
sigemptyset (&remote_fio_sa.sa_mask);
remote_fio_sa.sa_flags = 0;
sigaction (SIGINT, &remote_fio_sa, &remote_fio_osa);
#else
remote_fio_ofunc = signal (SIGINT, SIG_IGN);
#endif
}
static void
remote_fileio_sig_set (void (*sigint_func)(int))
{
#if defined (HAVE_SIGACTION) && defined (SA_RESTART)
remote_fio_sa.sa_handler = sigint_func;
sigemptyset (&remote_fio_sa.sa_mask);
remote_fio_sa.sa_flags = 0;
sigaction (SIGINT, &remote_fio_sa, NULL);
#else
signal (SIGINT, sigint_func);
#endif
}
static void
remote_fileio_sig_exit (void)
{
#if defined (HAVE_SIGACTION) && defined (SA_RESTART)
sigaction (SIGINT, &remote_fio_osa, NULL);
#else
signal (SIGINT, remote_fio_ofunc);
#endif
}
static void
remote_fileio_ctrl_c_signal_handler (int signo)
{
remote_fileio_sig_set (SIG_IGN);
remote_fio_ctrl_c_flag = 1;
if (!target_fio_no_longjmp)
deprecated_throw_reason (RETURN_QUIT);
remote_fileio_sig_set (remote_fileio_ctrl_c_signal_handler);
}
static void
remote_fileio_reply (int retcode, int error)
{
char buf[32];
remote_fileio_sig_set (SIG_IGN);
strcpy (buf, "F");
if (retcode < 0)
{
strcat (buf, "-");
retcode = -retcode;
}
sprintf (buf + strlen (buf), "%x", retcode);
if (error || remote_fio_ctrl_c_flag)
{
if (error && remote_fio_ctrl_c_flag)
error = FILEIO_EINTR;
if (error < 0)
{
strcat (buf, "-");
error = -error;
}
sprintf (buf + strlen (buf), ",%x", error);
if (remote_fio_ctrl_c_flag)
strcat (buf, ",C");
}
remote_fileio_sig_set (remote_fileio_ctrl_c_signal_handler);
putpkt (buf);
}
/* Wrapper function for remote_write_bytes() which has the disadvantage to
write only one packet, regardless of the requested number of bytes to
transfer. This wrapper calls remote_write_bytes() as often as needed. */
static int
remote_fileio_write_bytes (CORE_ADDR memaddr, gdb_byte *myaddr, int len)
{
int ret = 0, written;
while (len > 0 && (written = remote_write_bytes (memaddr, myaddr, len)) > 0)
{
len -= written;
memaddr += written;
myaddr += written;
ret += written;
}
return ret;
}
static void
set_ctrl_c_signal_handler(void)
{
remote_fileio_sig_set (remote_fileio_ctrl_c_signal_handler);
}
/* Close any open descriptors, and reinitialize the file mapping. */
void
remote_fileio_reset (void)
{
target_fileio_reset();
}
void
remote_fileio_request (char *buf)
{
static struct file_io_operations operations =
{
remote_read_bytes,
remote_fileio_write_bytes,
remote_fileio_reply,
set_ctrl_c_signal_handler
};
remote_fileio_sig_init ();
target_fileio_request(buf, &operations);
remote_fileio_sig_exit ();
}
void
initialize_remote_fileio (struct cmd_list_element *remote_set_cmdlist,
struct cmd_list_element *remote_show_cmdlist)
{
initialize_target_fileio(remote_set_cmdlist, remote_show_cmdlist);
}