/* Remote File-I/O communications
- Copyright 2003 Free Software Foundation, Inc.
+ Copyright (C) 2003, 2005, 2006, 2007, 2008, 2009, 2010
+ 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
+ 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,
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., 59 Temple Place - Suite 330,
- Boston, MA 02111-1307, USA. */
+ 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 "gdb_stat.h"
#include "exceptions.h"
#include "remote-fileio.h"
+#include "event-loop.h"
#include <fcntl.h>
#include <sys/time.h>
#ifdef __CYGWIN__
#include <sys/cygwin.h> /* For cygwin_conv_to_full_posix_path. */
+#include <cygwin/version.h>
+#if CYGWIN_VERSION_DLL_MAKE_COMBINED(CYGWIN_VERSION_API_MAJOR,CYGWIN_VERSION_API_MINOR) < 181
+# define CCP_POSIX_TO_WIN_A 0
+# define CCP_WIN_A_TO_POSIX 2
+# define cygwin_conv_path(op, from, to, size) \
+ (op == CCP_WIN_A_TO_POSIX) ? \
+ cygwin_conv_to_full_posix_path (from, to) : \
+ cygwin_conv_to_win32_path (from, to)
+#endif
#endif
#include <signal.h>
static int remote_fio_system_call_allowed = 0;
+static struct async_signal_handler *sigint_fileio_token;
+
static int
remote_fileio_init_fd_map (void)
{
static int
remote_fileio_resize_fd_map (void)
{
+ int i = remote_fio_data.fd_map_size;
+
if (!remote_fio_data.fd_map)
return remote_fileio_init_fd_map ();
remote_fio_data.fd_map_size += 10;
remote_fio_data.fd_map =
(int *) xrealloc (remote_fio_data.fd_map,
remote_fio_data.fd_map_size * sizeof (int));
+ for (; i < remote_fio_data.fd_map_size; i++)
+ remote_fio_data.fd_map[i] = FIO_FD_INVALID;
return remote_fio_data.fd_map_size - 10;
}
remote_fileio_fd_to_targetfd (int fd)
{
int target_fd = remote_fileio_next_free_fd ();
+
remote_fio_data.fd_map[target_fd] = fd;
return target_fd;
}
hmode |= S_IWUSR;
if (mode & FILEIO_S_IXUSR)
hmode |= S_IXUSR;
+#ifdef S_IRGRP
if (mode & FILEIO_S_IRGRP)
hmode |= S_IRGRP;
+#endif
+#ifdef S_IWGRP
if (mode & FILEIO_S_IWGRP)
hmode |= S_IWGRP;
+#endif
+#ifdef S_IXGRP
if (mode & FILEIO_S_IXGRP)
hmode |= S_IXGRP;
+#endif
if (mode & FILEIO_S_IROTH)
hmode |= S_IROTH;
+#ifdef S_IWOTH
if (mode & FILEIO_S_IWOTH)
hmode |= S_IWOTH;
+#endif
+#ifdef S_IXOTH
if (mode & FILEIO_S_IXOTH)
hmode |= S_IXOTH;
+#endif
return hmode;
}
{
mode_t tmode = 0;
- if (mode & S_IFREG)
+ if (S_ISREG(mode))
tmode |= FILEIO_S_IFREG;
- if (mode & S_IFDIR)
+ if (S_ISDIR(mode))
tmode |= FILEIO_S_IFDIR;
- if (mode & S_IFCHR)
+ if (S_ISCHR(mode))
tmode |= FILEIO_S_IFCHR;
if (mode & S_IRUSR)
tmode |= FILEIO_S_IRUSR;
tmode |= FILEIO_S_IWUSR;
if (mode & S_IXUSR)
tmode |= FILEIO_S_IXUSR;
+#ifdef S_IRGRP
if (mode & S_IRGRP)
tmode |= FILEIO_S_IRGRP;
+#endif
+#ifdef S_IWRGRP
if (mode & S_IWGRP)
tmode |= FILEIO_S_IWGRP;
+#endif
+#ifdef S_IXGRP
if (mode & S_IXGRP)
tmode |= FILEIO_S_IXGRP;
+#endif
if (mode & S_IROTH)
tmode |= FILEIO_S_IROTH;
+#ifdef S_IWOTH
if (mode & S_IWOTH)
tmode |= FILEIO_S_IWOTH;
+#endif
+#ifdef S_IXOTH
if (mode & S_IXOTH)
tmode |= FILEIO_S_IXOTH;
+#endif
return tmode;
}
static void
remote_fileio_to_fio_stat (struct stat *st, struct fio_stat *fst)
{
+ LONGEST blksize;
+
/* `st_dev' is set in the calling function */
remote_fileio_to_fio_uint ((long) st->st_ino, fst->fst_ino);
remote_fileio_to_fio_mode (st->st_mode, fst->fst_mode);
remote_fileio_to_fio_uint ((long) st->st_gid, fst->fst_gid);
remote_fileio_to_fio_uint ((long) st->st_rdev, fst->fst_rdev);
remote_fileio_to_fio_ulong ((LONGEST) st->st_size, fst->fst_size);
- remote_fileio_to_fio_ulong ((LONGEST) st->st_blksize, fst->fst_blksize);
+#ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
+ blksize = st->st_blksize;
+#else
+ blksize = 512;
+#endif
+ remote_fileio_to_fio_ulong (blksize, fst->fst_blksize);
#if HAVE_STRUCT_STAT_ST_BLOCKS
remote_fileio_to_fio_ulong ((LONGEST) st->st_blocks, fst->fst_blocks);
#else
/* FIXME: This is correct for DJGPP, but other systems that don't
have st_blocks, if any, might prefer 512 instead of st_blksize.
(eliz, 30-12-2003) */
- remote_fileio_to_fio_ulong (((LONGEST) st->st_size + st->st_blksize - 1)
- / (LONGEST) st->st_blksize,
+ remote_fileio_to_fio_ulong (((LONGEST) st->st_size + blksize - 1)
+ / blksize,
fst->fst_blocks);
#endif
remote_fileio_to_fio_time (st->st_atime, fst->fst_atime);
#endif
}
+static void
+async_remote_fileio_interrupt (gdb_client_data arg)
+{
+ deprecated_throw_reason (RETURN_QUIT);
+}
+
static void
remote_fileio_ctrl_c_signal_handler (int signo)
{
remote_fileio_sig_set (SIG_IGN);
remote_fio_ctrl_c_flag = 1;
if (!remote_fio_no_longjmp)
- deprecated_throw_reason (RETURN_QUIT);
+ gdb_call_async_signal_handler (sigint_fileio_token, 1);
remote_fileio_sig_set (remote_fileio_ctrl_c_signal_handler);
}
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, char *myaddr, int len)
+remote_fileio_write_bytes (CORE_ADDR memaddr, gdb_byte *myaddr, int len)
{
int ret = 0, written;
/* Request pathname using 'm' packet */
pathname = alloca (length);
- retlength = remote_read_bytes (ptrval, pathname, length);
+ retlength = remote_read_bytes (ptrval, (gdb_byte *) pathname, length);
if (retlength != length)
{
remote_fileio_ioerror ();
LONGEST lnum;
CORE_ADDR ptrval;
int fd, ret, retlength;
- char *buffer;
+ gdb_byte *buffer;
size_t length;
off_t old_offset, new_offset;
static char *remaining_buf = NULL;
static int remaining_length = 0;
- buffer = (char *) xmalloc (32768);
+ buffer = (gdb_byte *) xmalloc (16384);
if (remaining_buf)
{
remote_fio_no_longjmp = 1;
}
else
{
- ret = ui_file_read (gdb_stdtargin, buffer, 32767);
+ /* Windows (at least XP and Server 2003) has difficulty
+ with large reads from consoles. If a handle is
+ backed by a real console device, overly large reads
+ from the handle will fail and set errno == ENOMEM.
+ On a Windows Server 2003 system where I tested,
+ reading 26608 bytes from the console was OK, but
+ anything above 26609 bytes would fail. The limit has
+ been observed to vary on different systems. So, we
+ limit this read to something smaller than that - by a
+ safe margin, in case the limit depends on system
+ resources or version. */
+ ret = ui_file_read (gdb_stdtargin, (char *) buffer, 16383);
remote_fio_no_longjmp = 1;
if (ret > 0 && (size_t)ret > length)
{
}
break;
default:
- buffer = (char *) xmalloc (length);
+ buffer = (gdb_byte *) xmalloc (length);
/* POSIX defines EINTR behaviour of read in a weird way. It's allowed
for read() to return -1 even if "some" bytes have been read. It
has been corrected in SUSv2 but that doesn't help us much...
LONGEST lnum;
CORE_ADDR ptrval;
int fd, ret, retlength;
- char *buffer;
+ gdb_byte *buffer;
size_t length;
/* 1. Parameter: file descriptor */
}
length = (size_t) num;
- buffer = (char *) xmalloc (length);
+ buffer = (gdb_byte *) xmalloc (length);
retlength = remote_read_bytes (ptrval, buffer, length);
if (retlength != length)
{
{
case FIO_FD_CONSOLE_IN:
remote_fileio_badfd ();
+ xfree (buffer);
return;
case FIO_FD_CONSOLE_OUT:
- ui_file_write (target_fd == 1 ? gdb_stdtarg : gdb_stdtargerr, buffer,
- length);
+ ui_file_write (target_fd == 1 ? gdb_stdtarg : gdb_stdtargerr,
+ (char *) buffer, length);
gdb_flush (target_fd == 1 ? gdb_stdtarg : gdb_stdtargerr);
ret = length;
break;
static void
remote_fileio_func_rename (char *buf)
{
- CORE_ADDR ptrval;
- int length, retlength;
+ CORE_ADDR old_ptr, new_ptr;
+ int old_len, new_len, retlength;
char *oldpath, *newpath;
int ret, of, nf;
struct stat ost, nst;
/* 1. Parameter: Ptr to oldpath / length incl. trailing zero */
- if (remote_fileio_extract_ptr_w_len (&buf, &ptrval, &length))
+ if (remote_fileio_extract_ptr_w_len (&buf, &old_ptr, &old_len))
{
remote_fileio_ioerror ();
return;
}
- /* Request oldpath using 'm' packet */
- oldpath = alloca (length);
- retlength = remote_read_bytes (ptrval, oldpath, length);
- if (retlength != length)
+
+ /* 2. Parameter: Ptr to newpath / length incl. trailing zero */
+ if (remote_fileio_extract_ptr_w_len (&buf, &new_ptr, &new_len))
{
remote_fileio_ioerror ();
return;
}
- /* 2. Parameter: Ptr to newpath / length incl. trailing zero */
- if (remote_fileio_extract_ptr_w_len (&buf, &ptrval, &length))
+
+ /* Request oldpath using 'm' packet */
+ oldpath = alloca (old_len);
+ retlength = remote_read_bytes (old_ptr, (gdb_byte *) oldpath, old_len);
+ if (retlength != old_len)
{
remote_fileio_ioerror ();
return;
}
+
/* Request newpath using 'm' packet */
- newpath = alloca (length);
- retlength = remote_read_bytes (ptrval, newpath, length);
- if (retlength != length)
+ newpath = alloca (new_len);
+ retlength = remote_read_bytes (new_ptr, (gdb_byte *) newpath, new_len);
+ if (retlength != new_len)
{
remote_fileio_ioerror ();
return;
errno = EISDIR;
else
{
- char oldfullpath[PATH_MAX + 1];
- char newfullpath[PATH_MAX + 1];
+ char oldfullpath[PATH_MAX];
+ char newfullpath[PATH_MAX];
int len;
- cygwin_conv_to_full_posix_path (oldpath, oldfullpath);
- cygwin_conv_to_full_posix_path (newpath, newfullpath);
+ cygwin_conv_path (CCP_WIN_A_TO_POSIX, oldpath, oldfullpath,
+ PATH_MAX);
+ cygwin_conv_path (CCP_WIN_A_TO_POSIX, newpath, newfullpath,
+ PATH_MAX);
len = strlen (oldfullpath);
if (newfullpath[len] == '/'
&& !strncmp (oldfullpath, newfullpath, len))
}
/* Request pathname using 'm' packet */
pathname = alloca (length);
- retlength = remote_read_bytes (ptrval, pathname, length);
+ retlength = remote_read_bytes (ptrval, (gdb_byte *) pathname, length);
if (retlength != length)
{
remote_fileio_ioerror ();
static void
remote_fileio_func_stat (char *buf)
{
- CORE_ADDR ptrval;
- int ret, length, retlength;
+ CORE_ADDR statptr, nameptr;
+ int ret, namelength, retlength;
char *pathname;
LONGEST lnum;
struct stat st;
struct fio_stat fst;
/* 1. Parameter: Ptr to pathname / length incl. trailing zero */
- if (remote_fileio_extract_ptr_w_len (&buf, &ptrval, &length))
+ if (remote_fileio_extract_ptr_w_len (&buf, &nameptr, &namelength))
{
remote_fileio_ioerror ();
return;
}
- /* Request pathname using 'm' packet */
- pathname = alloca (length);
- retlength = remote_read_bytes (ptrval, pathname, length);
- if (retlength != length)
+
+ /* 2. Parameter: Ptr to struct stat */
+ if (remote_fileio_extract_long (&buf, &lnum))
{
remote_fileio_ioerror ();
return;
}
-
- /* 2. Parameter: Ptr to struct stat */
- if (remote_fileio_extract_long (&buf, &lnum))
+ statptr = (CORE_ADDR) lnum;
+
+ /* Request pathname using 'm' packet */
+ pathname = alloca (namelength);
+ retlength = remote_read_bytes (nameptr, (gdb_byte *) pathname, namelength);
+ if (retlength != namelength)
{
remote_fileio_ioerror ();
return;
}
- ptrval = (CORE_ADDR) lnum;
remote_fio_no_longjmp = 1;
ret = stat (pathname, &st);
remote_fileio_reply (-1, FILEIO_EACCES);
return;
}
- if (ptrval)
+ if (statptr)
{
remote_fileio_to_fio_stat (&st, &fst);
remote_fileio_to_fio_uint (0, fst.fst_dev);
- retlength = remote_fileio_write_bytes (ptrval, (char *) &fst, sizeof fst);
+ retlength = remote_fileio_write_bytes (statptr,
+ (gdb_byte *) &fst, sizeof fst);
if (retlength != sizeof fst)
{
remote_fileio_return_errno (-1);
remote_fileio_to_fio_uint (1, fst.fst_dev);
st.st_mode = S_IFCHR | (fd == FIO_FD_CONSOLE_IN ? S_IRUSR : S_IWUSR);
st.st_nlink = 1;
+#ifdef HAVE_GETUID
st.st_uid = getuid ();
+#else
+ st.st_uid = 0;
+#endif
+#ifdef HAVE_GETGID
st.st_gid = getgid ();
+#else
+ st.st_gid = 0;
+#endif
st.st_rdev = 0;
st.st_size = 0;
+#ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
st.st_blksize = 512;
+#endif
#if HAVE_STRUCT_STAT_ST_BLOCKS
st.st_blocks = 0;
#endif
{
remote_fileio_to_fio_stat (&st, &fst);
- retlength = remote_fileio_write_bytes (ptrval, (char *) &fst, sizeof fst);
+ retlength = remote_fileio_write_bytes (ptrval, (gdb_byte *) &fst, sizeof fst);
if (retlength != sizeof fst)
{
remote_fileio_return_errno (-1);
{
remote_fileio_to_fio_timeval (&tv, &ftv);
- retlength = remote_fileio_write_bytes (ptrval, (char *) &ftv, sizeof ftv);
+ retlength = remote_fileio_write_bytes (ptrval, (gdb_byte *) &ftv, sizeof ftv);
if (retlength != sizeof ftv)
{
remote_fileio_return_errno (-1);
{
CORE_ADDR ptrval;
int ret, length, retlength;
- char *cmdline;
-
- /* Check if system(3) has been explicitely allowed using the
- `set remote system-call-allowed 1' command. If not, return
- EPERM */
- if (!remote_fio_system_call_allowed)
- {
- remote_fileio_reply (-1, FILEIO_EPERM);
- return;
- }
+ char *cmdline = NULL;
/* Parameter: Ptr to commandline / length incl. trailing zero */
if (remote_fileio_extract_ptr_w_len (&buf, &ptrval, &length))
remote_fileio_ioerror ();
return;
}
- /* Request commandline using 'm' packet */
- cmdline = alloca (length);
- retlength = remote_read_bytes (ptrval, cmdline, length);
- if (retlength != length)
+
+ if (length)
{
- remote_fileio_ioerror ();
+ /* Request commandline using 'm' packet */
+ cmdline = alloca (length);
+ retlength = remote_read_bytes (ptrval, (gdb_byte *) cmdline, length);
+ if (retlength != length)
+ {
+ remote_fileio_ioerror ();
+ return;
+ }
+ }
+
+ /* Check if system(3) has been explicitely allowed using the
+ `set remote system-call-allowed 1' command. If length is 0,
+ indicating a NULL parameter to the system call, return zero to
+ indicate a shell is not available. Otherwise fail with EPERM. */
+ if (!remote_fio_system_call_allowed)
+ {
+ if (!length)
+ remote_fileio_return_success (0);
+ else
+ remote_fileio_reply (-1, FILEIO_EPERM);
return;
}
remote_fio_no_longjmp = 1;
ret = system (cmdline);
- if (ret == -1)
+ if (!length)
+ remote_fileio_return_success (ret);
+ else if (ret == -1)
remote_fileio_return_errno (-1);
else
remote_fileio_return_success (WEXITSTATUS (ret));
char *name;
void (*func)(char *);
} remote_fio_func_map[] = {
- "open", remote_fileio_func_open,
- "close", remote_fileio_func_close,
- "read", remote_fileio_func_read,
- "write", remote_fileio_func_write,
- "lseek", remote_fileio_func_lseek,
- "rename", remote_fileio_func_rename,
- "unlink", remote_fileio_func_unlink,
- "stat", remote_fileio_func_stat,
- "fstat", remote_fileio_func_fstat,
- "gettimeofday", remote_fileio_func_gettimeofday,
- "isatty", remote_fileio_func_isatty,
- "system", remote_fileio_func_system,
- NULL, NULL
+ { "open", remote_fileio_func_open },
+ { "close", remote_fileio_func_close },
+ { "read", remote_fileio_func_read },
+ { "write", remote_fileio_func_write },
+ { "lseek", remote_fileio_func_lseek },
+ { "rename", remote_fileio_func_rename },
+ { "unlink", remote_fileio_func_unlink },
+ { "stat", remote_fileio_func_stat },
+ { "fstat", remote_fileio_func_fstat },
+ { "gettimeofday", remote_fileio_func_gettimeofday },
+ { "isatty", remote_fileio_func_isatty },
+ { "system", remote_fileio_func_system },
+ { NULL, NULL }
};
static int
return 0;
}
+/* Close any open descriptors, and reinitialize the file mapping. */
+
+void
+remote_fileio_reset (void)
+{
+ int ix;
+
+ for (ix = 0; ix != remote_fio_data.fd_map_size; ix++)
+ {
+ int fd = remote_fio_data.fd_map[ix];
+
+ if (fd >= 0)
+ close (fd);
+ }
+ if (remote_fio_data.fd_map)
+ {
+ xfree (remote_fio_data.fd_map);
+ remote_fio_data.fd_map = NULL;
+ remote_fio_data.fd_map_size = 0;
+ }
+}
+
+/* Handle a file I/O request. BUF points to the packet containing the
+ request. CTRLC_PENDING_P should be nonzero if the target has not
+ acknowledged the Ctrl-C sent asynchronously earlier. */
+
void
-remote_fileio_request (char *buf)
+remote_fileio_request (char *buf, int ctrlc_pending_p)
{
int ex;
remote_fileio_sig_init ();
- remote_fio_ctrl_c_flag = 0;
- remote_fio_no_longjmp = 0;
-
- ex = catch_exceptions (uiout, do_remote_fileio_request, (void *)buf,
- RETURN_MASK_ALL);
- switch (ex)
+ if (ctrlc_pending_p)
{
- case RETURN_ERROR:
- remote_fileio_reply (-1, FILEIO_ENOSYS);
- break;
- case RETURN_QUIT:
- remote_fileio_reply (-1, FILEIO_EINTR);
- break;
- default:
- break;
+ /* If the target hasn't responded to the Ctrl-C sent
+ asynchronously earlier, take this opportunity to send the
+ Ctrl-C synchronously. */
+ remote_fio_ctrl_c_flag = 1;
+ remote_fio_no_longjmp = 0;
+ remote_fileio_reply (-1, FILEIO_EINTR);
+ }
+ else
+ {
+ remote_fio_ctrl_c_flag = 0;
+ remote_fio_no_longjmp = 0;
+
+ ex = catch_exceptions (uiout, do_remote_fileio_request, (void *)buf,
+ RETURN_MASK_ALL);
+ switch (ex)
+ {
+ case RETURN_ERROR:
+ remote_fileio_reply (-1, FILEIO_ENOSYS);
+ break;
+ case RETURN_QUIT:
+ remote_fileio_reply (-1, FILEIO_EINTR);
+ break;
+ default:
+ break;
+ }
}
remote_fileio_sig_exit ();
{
char *arg_end;
int val = strtoul (args, &arg_end, 10);
+
if (*args && *arg_end == '\0')
{
remote_fio_system_call_allowed = !!val;
initialize_remote_fileio (struct cmd_list_element *remote_set_cmdlist,
struct cmd_list_element *remote_show_cmdlist)
{
+ sigint_fileio_token =
+ create_async_signal_handler (async_remote_fileio_interrupt, NULL);
+
add_cmd ("system-call-allowed", no_class,
set_system_call_allowed,
_("Set if the host system(3) call is allowed for the target."),