From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 1551) id 8C2D23858D32; Tue, 26 Jul 2022 18:46:39 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 8C2D23858D32 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable From: Pedro Alves To: gdb-cvs@sourceware.org Subject: [binutils-gdb] gdb/linux-nat: Check whether /proc/pid/mem is writable X-Act-Checkin: binutils-gdb X-Git-Author: Pedro Alves X-Git-Refname: refs/heads/master X-Git-Oldrev: ecbff28a4457d0ebe11023fa9671d62251e7463d X-Git-Newrev: 1bcb0708f22956d5128a2e75df6eba5a18327892 Message-Id: <20220726184639.8C2D23858D32@sourceware.org> Date: Tue, 26 Jul 2022 18:46:39 +0000 (GMT) X-BeenThere: gdb-cvs@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gdb-cvs mailing list List-Unsubscribe: , List-Archive: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 26 Jul 2022 18:46:39 -0000 https://sourceware.org/git/gitweb.cgi?p=3Dbinutils-gdb.git;h=3D1bcb0708f229= 56d5128a2e75df6eba5a18327892 commit 1bcb0708f22956d5128a2e75df6eba5a18327892 Author: Pedro Alves Date: Thu Jul 21 19:11:16 2022 +0100 gdb/linux-nat: Check whether /proc/pid/mem is writable =20 Probe whether /proc/pid/mem is writable, by using it to write to a GDB variable. This will be used in the following patch to avoid falling back to writing to inferior memory with ptrace if /proc/pid/mem _is_ writable. =20 Change-Id: If87eff0b46cbe5e32a583e2977a9e17d29d0ed3e Diff: --- gdb/linux-nat.c | 105 +++++++++++++++++++++++++++++++++++++++++++++++-----= ---- 1 file changed, 88 insertions(+), 17 deletions(-) diff --git a/gdb/linux-nat.c b/gdb/linux-nat.c index a2bbd3cbfc8..b641e88b1ef 100644 --- a/gdb/linux-nat.c +++ b/gdb/linux-nat.c @@ -244,6 +244,7 @@ static int lwp_status_pending_p (struct lwp_info *lp); =20 static void save_stop_reason (struct lwp_info *lp); =20 +static bool proc_mem_file_is_writable (); static void close_proc_mem_file (pid_t pid); static void open_proc_mem_file (ptid_t ptid); =20 @@ -3882,25 +3883,19 @@ open_proc_mem_file (ptid_t ptid) fd, ptid.pid (), ptid.lwp ()); } =20 -/* Implement the to_xfer_partial target method using /proc/PID/mem. - Because we can use a single read/write call, this can be much more - efficient than banging away at PTRACE_PEEKTEXT. Also, unlike - PTRACE_PEEKTEXT/PTRACE_POKETEXT, this works with running - threads. */ +/* Helper for linux_proc_xfer_memory_partial and + proc_mem_file_is_writable. FD is the already opened /proc/pid/mem + file, and PID is the pid of the corresponding process. The rest of + the arguments are like linux_proc_xfer_memory_partial's. */ =20 static enum target_xfer_status -linux_proc_xfer_memory_partial (gdb_byte *readbuf, const gdb_byte *writebu= f, - ULONGEST offset, LONGEST len, - ULONGEST *xfered_len) +linux_proc_xfer_memory_partial_fd (int fd, int pid, + gdb_byte *readbuf, const gdb_byte *writebuf, + ULONGEST offset, LONGEST len, + ULONGEST *xfered_len) { ssize_t ret; =20 - auto iter =3D proc_mem_file_map.find (inferior_ptid.pid ()); - if (iter =3D=3D proc_mem_file_map.end ()) - return TARGET_XFER_EOF; - - int fd =3D iter->second.fd (); - gdb_assert (fd !=3D -1); =20 /* Use pread64/pwrite64 if available, since they save a syscall and can @@ -3919,8 +3914,7 @@ linux_proc_xfer_memory_partial (gdb_byte *readbuf, co= nst gdb_byte *writebuf, if (ret =3D=3D -1) { linux_nat_debug_printf ("accessing fd %d for pid %d failed: %s (%d)", - fd, inferior_ptid.pid (), - safe_strerror (errno), errno); + fd, pid, safe_strerror (errno), errno); return TARGET_XFER_E_IO; } else if (ret =3D=3D 0) @@ -3928,7 +3922,7 @@ linux_proc_xfer_memory_partial (gdb_byte *readbuf, co= nst gdb_byte *writebuf, /* EOF means the address space is gone, the whole process exited or execed. */ linux_nat_debug_printf ("accessing fd %d for pid %d got EOF", - fd, inferior_ptid.pid ()); + fd, pid); return TARGET_XFER_EOF; } else @@ -3938,6 +3932,81 @@ linux_proc_xfer_memory_partial (gdb_byte *readbuf, c= onst gdb_byte *writebuf, } } =20 +/* Implement the to_xfer_partial target method using /proc/PID/mem. + Because we can use a single read/write call, this can be much more + efficient than banging away at PTRACE_PEEKTEXT. Also, unlike + PTRACE_PEEKTEXT/PTRACE_POKETEXT, this works with running + threads. */ + +static enum target_xfer_status +linux_proc_xfer_memory_partial (gdb_byte *readbuf, const gdb_byte *writebu= f, + ULONGEST offset, LONGEST len, + ULONGEST *xfered_len) +{ + int pid =3D inferior_ptid.pid (); + + auto iter =3D proc_mem_file_map.find (pid); + if (iter =3D=3D proc_mem_file_map.end ()) + return TARGET_XFER_EOF; + + int fd =3D iter->second.fd (); + + return linux_proc_xfer_memory_partial_fd (fd, pid, readbuf, writebuf, of= fset, + len, xfered_len); +} + +/* Check whether /proc/pid/mem is writable in the current kernel, and + return true if so. It wasn't writable before Linux 2.6.39, but + there's no way to know whether the feature was backported to older + kernels. So we check to see if it works. The result is cached, + and this is garanteed to be called once early at startup. */ + +static bool +proc_mem_file_is_writable () +{ + static gdb::optional writable; + + if (writable.has_value ()) + return *writable; + + writable.emplace (false); + + /* We check whether /proc/pid/mem is writable by trying to write to + one of our variables via /proc/self/mem. */ + + int fd =3D gdb_open_cloexec ("/proc/self/mem", O_RDWR | O_LARGEFILE, 0).= release (); + + if (fd =3D=3D -1) + { + warning (_("opening /proc/self/mem file failed: %s (%d)"), + safe_strerror (errno), errno); + return *writable; + } + + SCOPE_EXIT { close (fd); }; + + /* This is the variable we try to write to. Note OFFSET below. */ + volatile gdb_byte test_var =3D 0; + + gdb_byte writebuf[] =3D {0x55}; + ULONGEST offset =3D (uintptr_t) &test_var; + ULONGEST xfered_len; + + enum target_xfer_status res + =3D linux_proc_xfer_memory_partial_fd (fd, getpid (), nullptr, writebu= f, + offset, 1, &xfered_len); + + if (res =3D=3D TARGET_XFER_OK) + { + gdb_assert (xfered_len =3D=3D 1); + gdb_assert (test_var =3D=3D 0x55); + /* Success. */ + *writable =3D true; + } + + return *writable; +} + /* Parse LINE as a signal set and add its set bits to SIGS. */ =20 static void @@ -4437,6 +4506,8 @@ Enables printf debugging output."), sigemptyset (&blocked_mask); =20 lwp_lwpid_htab_create (); + + proc_mem_file_is_writable (); }