summaryrefslogtreecommitdiff
path: root/gdb/common
diff options
context:
space:
mode:
authorTom Tromey <tromey@redhat.com>2013-04-22 16:46:14 +0000
committerTom Tromey <tromey@redhat.com>2013-04-22 16:46:14 +0000
commitceff6a55e34396c81009e9c93086e7fa84eb73ec (patch)
tree615eb5cb7fe870d33d124c034e7fa4387c105ac5 /gdb/common
parentc8672d57d6e470057494b26e1a3c58d6b9e45ebe (diff)
downloadgdb-ceff6a55e34396c81009e9c93086e7fa84eb73ec.tar.gz
PR gdb/7912:
* Makefile.in (SFILES): Add filestuff.c (COMMON_OBS): Add filestuff.o. (filestuff.o): New target. * auto-load.c (auto_load_objfile_script_1): Use gdb_fopen_cloexec. * auxv.c (procfs_xfer_auxv): Use gdb_open_cloexec. * cli/cli-cmds.c (shell_escape): Call close_most_fds. * cli/cli-dump.c (fopen_with_cleanup): Use gdb_fopen_cloexec. * common/agent.c (gdb_connect_sync_socket): Use gdb_socket_cloexec. * common/filestuff.c: New file. * common/filestuff.h: New file. * common/linux-osdata.c (linux_common_core_of_thread) (command_from_pid, commandline_from_pid, print_source_lines) (linux_xfer_osdata_shm, linux_xfer_osdata_sem) (linux_xfer_osdata_msg, linux_xfer_osdata_modules): Use gdb_fopen_cloexec. * common/linux-procfs.c (linux_proc_get_int) (linux_proc_pid_has_state): Use gdb_fopen_cloexec. * config.in, configure: Rebuild. * configure.ac: Don't check for sys/socket.h. Check for fdwalk, pipe2. * corelow.c (core_open): Use gdb_open_cloexec. * dwarf2read.c (write_psymtabs_to_index): Use gdb_fopen_cloexec. * fork-child.c (fork_inferior): Call close_most_fds. * gdb_bfd.c (gdb_bfd_open): Use gdb_open_cloexec. * inf-child.c (inf_child_fileio_readlink): Use gdb_open_cloexec. * linux-nat.c (linux_nat_thread_name, linux_proc_pending_signals): Use gdb_fopen_cloexec. (linux_proc_xfer_partial, linux_proc_xfer_spu): Use gdb_open_cloexec. (linux_async_pipe): Use gdb_pipe_cloexec. * remote-fileio.c (remote_fileio_func_open): Use gdb_open_cloexec. * remote.c (remote_file_put, remote_file_get): Use gdb_fopen_cloexec. * ser-pipe.c (pipe_open): Use gdb_socketpair_cloexec, close_most_fds. * ser-tcp.c (net_open): Use gdb_socket_cloexec. * ser-unix.c (hardwire_open): Use gdb_open_cloexec. * solib.c (solib_find): Use gdb_open_cloexec. * source.c (openp, find_and_open_source): Use gdb_open_cloexec. * tracepoint.c (tfile_start): Use gdb_fopen_cloexec. (tfile_open): Use gdb_open_cloexec. * tui/tui-io.c (tui_initialize_io): Use gdb_pipe_cloexec. * ui-file.c (gdb_fopen): Use gdb_fopen_cloexec. * xml-support.c (xml_fetch_content_from_file): Use gdb_fopen_cloexec. * main.c (captured_main): Call notice_open_fds. gdbserver * Makefile.in (SFILES): Add filestuff.c. (OBS): Add filestuff.o. (filestuff.o): New target. * config.in, configure: Rebuild. * configure.ac: Check for fdwalk, pipe2.
Diffstat (limited to 'gdb/common')
-rw-r--r--gdb/common/agent.c3
-rw-r--r--gdb/common/filestuff.c354
-rw-r--r--gdb/common/filestuff.h59
-rw-r--r--gdb/common/linux-osdata.c17
-rw-r--r--gdb/common/linux-procfs.c5
5 files changed, 427 insertions, 11 deletions
diff --git a/gdb/common/agent.c b/gdb/common/agent.c
index f7bedc2c874..99cef4fcab3 100644
--- a/gdb/common/agent.c
+++ b/gdb/common/agent.c
@@ -28,6 +28,7 @@
#include <string.h>
#include <unistd.h>
#include "agent.h"
+#include "filestuff.h"
int debug_agent = 0;
@@ -168,7 +169,7 @@ gdb_connect_sync_socket (int pid)
if (res >= UNIX_PATH_MAX)
return -1;
- res = fd = socket (PF_UNIX, SOCK_STREAM, 0);
+ res = fd = gdb_socket_cloexec (PF_UNIX, SOCK_STREAM, 0);
if (res == -1)
{
warning (_("error opening sync socket: %s"), strerror (errno));
diff --git a/gdb/common/filestuff.c b/gdb/common/filestuff.c
new file mode 100644
index 00000000000..2cc1c4d1662
--- /dev/null
+++ b/gdb/common/filestuff.c
@@ -0,0 +1,354 @@
+/* Low-level file-handling.
+ Copyright (C) 2012, 2013 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/>. */
+
+#ifdef GDBSERVER
+#include "server.h"
+#else
+#include "defs.h"
+#include "gdb_string.h"
+#endif
+#include "filestuff.h"
+#include "gdb_vecs.h"
+
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#ifdef HAVE_SYS_RESOURCE_H
+#include <sys/resource.h>
+#endif /* HAVE_SYS_RESOURCE_H */
+
+#ifndef O_CLOEXEC
+#define O_CLOEXEC 0
+#endif
+
+#ifndef SOCK_CLOEXEC
+#define SOCK_CLOEXEC 0
+#endif
+
+
+
+#ifndef HAVE_FDWALK
+
+#include <dirent.h>
+
+/* Replacement for fdwalk, if the system doesn't define it. Walks all
+ open file descriptors (though this implementation may walk closed
+ ones as well, depending on the host platform's capabilities) and
+ call FUNC with ARG. If FUNC returns non-zero, stops immediately
+ and returns the same value. Otherwise, returns zero when
+ finished. */
+
+static int
+fdwalk (int (*func) (void *, int), void *arg)
+{
+ /* Checking __linux__ isn't great but it isn't clear what would be
+ better. There doesn't seem to be a good way to check for this in
+ configure. */
+#ifdef __linux__
+ DIR *dir;
+
+ dir = opendir ("/proc/self/fd");
+ if (dir != NULL)
+ {
+ struct dirent *entry;
+ int result = 0;
+
+ for (entry = readdir (dir); entry != NULL; entry = readdir (dir))
+ {
+ long fd;
+ char *tail;
+ int result;
+
+ errno = 0;
+ fd = strtol (entry->d_name, &tail, 10);
+ if (*tail != '\0' || errno != 0)
+ continue;
+ if ((int) fd != fd)
+ {
+ /* What can we do here really? */
+ continue;
+ }
+
+ if (fd == dirfd (dir))
+ continue;
+
+ result = func (arg, fd);
+ if (result != 0)
+ break;
+ }
+
+ closedir (dir);
+ return result;
+ }
+ /* We may fall through to the next case. */
+#endif
+
+ {
+ int max, fd;
+
+#ifdef HAVE_GETRLIMIT
+ struct rlimit rlim;
+
+ if (getrlimit (RLIMIT_NOFILE, &rlim) == 0 && rlim.rlim_max != RLIM_INFINITY)
+ max = rlim.rlim_max;
+ else
+#endif
+ {
+#ifdef _SC_OPEN_MAX
+ max = sysconf (_SC_OPEN_MAX);
+#else
+ /* Whoops. */
+ return 0;
+#endif /* _SC_OPEN_MAX */
+ }
+
+ for (fd = 0; fd < max; ++fd)
+ {
+ struct stat sb;
+ int result;
+
+ /* Only call FUNC for open fds. */
+ if (fstat (fd, &sb) == -1)
+ continue;
+
+ result = func (arg, fd);
+ if (result != 0)
+ return result;
+ }
+
+ return 0;
+ }
+}
+
+#endif /* HAVE_FDWALK */
+
+
+
+/* A VEC holding all the fds open when notice_open_fds was called. We
+ don't use a hashtab because libiberty isn't linked into gdbserver;
+ and anyway we don't expect there to be many open fds. */
+
+DEF_VEC_I (int);
+
+static VEC (int) *open_fds;
+
+/* An fdwalk callback function used by notice_open_fds. It puts the
+ given file descriptor into the vec. */
+
+static int
+do_mark_open_fd (void *ignore, int fd)
+{
+ VEC_safe_push (int, open_fds, fd);
+ return 0;
+}
+
+/* See filestuff.h. */
+
+void
+notice_open_fds (void)
+{
+ fdwalk (do_mark_open_fd, NULL);
+}
+
+/* Helper function for close_most_fds that closes the file descriptor
+ if appropriate. */
+
+static int
+do_close (void *ignore, int fd)
+{
+ int i, val;
+
+ for (i = 0; VEC_iterate (int, open_fds, i, val); ++i)
+ {
+ if (fd == val)
+ {
+ /* Keep this one open. */
+ return 0;
+ }
+ }
+
+ close (fd);
+ return 0;
+}
+
+/* See filestuff.h. */
+
+void
+close_most_fds (void)
+{
+ fdwalk (do_close, NULL);
+}
+
+
+
+/* This is a tri-state flag. When zero it means we haven't yet tried
+ O_CLOEXEC. When positive it means that O_CLOEXEC works on this
+ host. When negative, it means that O_CLOEXEC doesn't work. We
+ track this state because, while gdb might have been compiled
+ against a libc that supplies O_CLOEXEC, there is no guarantee that
+ the kernel supports it. */
+
+static int trust_o_cloexec;
+
+/* Mark FD as close-on-exec, ignoring errors. Update
+ TRUST_O_CLOEXEC. */
+
+static void
+mark_cloexec (int fd)
+{
+ int old = fcntl (fd, F_GETFD, 0);
+
+ if (old != -1)
+ {
+ fcntl (fd, F_SETFD, old | FD_CLOEXEC);
+
+ if (trust_o_cloexec == 0)
+ {
+ if ((old & FD_CLOEXEC) != 0)
+ trust_o_cloexec = 1;
+ else
+ trust_o_cloexec = -1;
+ }
+ }
+}
+
+/* Depending on TRUST_O_CLOEXEC, mark FD as close-on-exec. */
+
+static void
+maybe_mark_cloexec (int fd)
+{
+ if (trust_o_cloexec <= 0)
+ mark_cloexec (fd);
+}
+
+/* Like maybe_mark_cloexec, but for callers that use SOCK_CLOEXEC. */
+
+static void
+socket_mark_cloexec (int fd)
+{
+ if (SOCK_CLOEXEC == 0 || trust_o_cloexec <= 0)
+ mark_cloexec (fd);
+}
+
+
+
+/* See filestuff.h. */
+
+int
+gdb_open_cloexec (const char *filename, int flags, mode_t mode)
+{
+ int fd = open (filename, flags | O_CLOEXEC, mode);
+
+ if (fd >= 0)
+ maybe_mark_cloexec (fd);
+
+ return fd;
+}
+
+/* See filestuff.h. */
+
+FILE *
+gdb_fopen_cloexec (const char *filename, const char *opentype)
+{
+ FILE *result = NULL;
+ static int fopen_e_ever_failed;
+
+ if (!fopen_e_ever_failed)
+ {
+ char *copy;
+
+ copy = alloca (strlen (opentype) + 2);
+ strcpy (copy, opentype);
+ /* This is a glibc extension but we try it unconditionally on
+ this path. */
+ strcat (copy, "e");
+ result = fopen (filename, copy);
+ }
+
+ if (result == NULL)
+ {
+ /* Fallback. */
+ result = fopen (filename, opentype);
+ if (result != NULL)
+ fopen_e_ever_failed = 1;
+ }
+
+ if (result != NULL)
+ maybe_mark_cloexec (fileno (result));
+
+ return result;
+}
+
+/* See filestuff.h. */
+
+int
+gdb_socketpair_cloexec (int namespace, int style, int protocol, int filedes[2])
+{
+ int result = socketpair (namespace, style | SOCK_CLOEXEC, protocol, filedes);
+
+ if (result != -1)
+ {
+ socket_mark_cloexec (filedes[0]);
+ socket_mark_cloexec (filedes[1]);
+ }
+
+ return result;
+}
+
+/* See filestuff.h. */
+
+int
+gdb_socket_cloexec (int namespace, int style, int protocol)
+{
+ int result = socket (namespace, style | SOCK_CLOEXEC, protocol);
+
+ if (result != -1)
+ socket_mark_cloexec (result);
+
+ return result;
+}
+
+/* See filestuff.h. */
+
+int
+gdb_pipe_cloexec (int filedes[2])
+{
+ int result;
+
+#ifdef HAVE_PIPE2
+ result = pipe2 (filedes, O_CLOEXEC);
+ if (result != -1)
+ {
+ maybe_mark_cloexec (filedes[0]);
+ maybe_mark_cloexec (filedes[1]);
+ }
+#else
+ result = pipe (filedes);
+ if (result != -1)
+ {
+ mark_cloexec (filedes[0]);
+ mark_cloexec (filedes[1]);
+ }
+#endif
+
+ return result;
+}
diff --git a/gdb/common/filestuff.h b/gdb/common/filestuff.h
new file mode 100644
index 00000000000..747bff24945
--- /dev/null
+++ b/gdb/common/filestuff.h
@@ -0,0 +1,59 @@
+/* Low-level file-handling.
+ Copyright (C) 2012, 2013 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/>. */
+
+#ifndef FILESTUFF_H
+#define FILESTUFF_H
+
+/* Note all the file descriptors which are open when this is called.
+ These file descriptors will not be closed by close_most_fds. */
+
+extern void notice_open_fds (void);
+
+/* Close all open file descriptors other than those marked by
+ 'notice_open_fds', and stdin, stdout, and stderr. Errors that
+ occur while closing are ignored. */
+
+extern void close_most_fds (void);
+
+/* Like 'open', but ensures that the returned file descriptor has the
+ close-on-exec flag set. */
+
+extern int gdb_open_cloexec (const char *filename, int flags, mode_t mode);
+
+/* Like 'fopen', but ensures that the returned file descriptor has the
+ close-on-exec flag set. */
+
+extern FILE *gdb_fopen_cloexec (const char *filename, const char *opentype);
+
+/* Like 'socketpair', but ensures that the returned file descriptors
+ have the close-on-exec flag set. */
+
+extern int gdb_socketpair_cloexec (int namespace, int style, int protocol,
+ int filedes[2]);
+
+/* Like 'socket', but ensures that the returned file descriptor has
+ the close-on-exec flag set. */
+
+extern int gdb_socket_cloexec (int namespace, int style, int protocol);
+
+/* Like 'pipe', but ensures that the returned file descriptors have
+ the close-on-exec flag set. */
+
+extern int gdb_pipe_cloexec (int filedes[2]);
+
+#endif /* FILESTUFF_H */
diff --git a/gdb/common/linux-osdata.c b/gdb/common/linux-osdata.c
index d55470b9faa..9723839525d 100644
--- a/gdb/common/linux-osdata.c
+++ b/gdb/common/linux-osdata.c
@@ -44,6 +44,7 @@
#include "gdb_assert.h"
#include "gdb_dirent.h"
#include "gdb_stat.h"
+#include "filestuff.h"
/* Define PID_T to be a fixed size that is at least as large as pid_t,
so that reading pid values embedded in /proc works
@@ -76,7 +77,7 @@ linux_common_core_of_thread (ptid_t ptid)
sprintf (filename, "/proc/%lld/task/%lld/stat",
(PID_T) ptid_get_pid (ptid), (PID_T) ptid_get_lwp (ptid));
- f = fopen (filename, "r");
+ f = gdb_fopen_cloexec (filename, "r");
if (!f)
return -1;
@@ -125,7 +126,7 @@ static void
command_from_pid (char *command, int maxlen, PID_T pid)
{
char *stat_path = xstrprintf ("/proc/%lld/stat", pid);
- FILE *fp = fopen (stat_path, "r");
+ FILE *fp = gdb_fopen_cloexec (stat_path, "r");
command[0] = '\0';
@@ -165,7 +166,7 @@ commandline_from_pid (PID_T pid)
{
char *pathname = xstrprintf ("/proc/%lld/cmdline", pid);
char *commandline = NULL;
- FILE *f = fopen (pathname, "r");
+ FILE *f = gdb_fopen_cloexec (pathname, "r");
if (f)
{
@@ -860,7 +861,7 @@ print_sockets (unsigned short family, int tcp, struct buffer *buffer)
else
return;
- fp = fopen (proc_file, "r");
+ fp = gdb_fopen_cloexec (proc_file, "r");
if (fp)
{
char buf[8192];
@@ -1088,7 +1089,7 @@ linux_xfer_osdata_shm (gdb_byte *readbuf,
buffer_init (&buffer);
buffer_grow_str (&buffer, "<osdata type=\"shared memory\">\n");
- fp = fopen ("/proc/sysvipc/shm", "r");
+ fp = gdb_fopen_cloexec ("/proc/sysvipc/shm", "r");
if (fp)
{
char buf[8192];
@@ -1216,7 +1217,7 @@ linux_xfer_osdata_sem (gdb_byte *readbuf,
buffer_init (&buffer);
buffer_grow_str (&buffer, "<osdata type=\"semaphores\">\n");
- fp = fopen ("/proc/sysvipc/sem", "r");
+ fp = gdb_fopen_cloexec ("/proc/sysvipc/sem", "r");
if (fp)
{
char buf[8192];
@@ -1328,7 +1329,7 @@ linux_xfer_osdata_msg (gdb_byte *readbuf,
buffer_init (&buffer);
buffer_grow_str (&buffer, "<osdata type=\"message queues\">\n");
- fp = fopen ("/proc/sysvipc/msg", "r");
+ fp = gdb_fopen_cloexec ("/proc/sysvipc/msg", "r");
if (fp)
{
char buf[8192];
@@ -1454,7 +1455,7 @@ linux_xfer_osdata_modules (gdb_byte *readbuf,
buffer_init (&buffer);
buffer_grow_str (&buffer, "<osdata type=\"modules\">\n");
- fp = fopen ("/proc/modules", "r");
+ fp = gdb_fopen_cloexec ("/proc/modules", "r");
if (fp)
{
char buf[8192];
diff --git a/gdb/common/linux-procfs.c b/gdb/common/linux-procfs.c
index f5dccfd3720..583ec98393d 100644
--- a/gdb/common/linux-procfs.c
+++ b/gdb/common/linux-procfs.c
@@ -24,6 +24,7 @@
#endif
#include "linux-procfs.h"
+#include "filestuff.h"
/* Return the TGID of LWPID from /proc/pid/status. Returns -1 if not
found. */
@@ -37,7 +38,7 @@ linux_proc_get_int (pid_t lwpid, const char *field)
int retval = -1;
snprintf (buf, sizeof (buf), "/proc/%d/status", (int) lwpid);
- status_file = fopen (buf, "r");
+ status_file = gdb_fopen_cloexec (buf, "r");
if (status_file == NULL)
{
warning (_("unable to open /proc file '%s'"), buf);
@@ -83,7 +84,7 @@ linux_proc_pid_has_state (pid_t pid, const char *state)
int have_state;
xsnprintf (buffer, sizeof (buffer), "/proc/%d/status", (int) pid);
- procfile = fopen (buffer, "r");
+ procfile = gdb_fopen_cloexec (buffer, "r");
if (procfile == NULL)
{
warning (_("unable to open /proc file '%s'"), buffer);