qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: Richard Henderson <richard.henderson@linaro.org>
To: qemu-devel@nongnu.org
Cc: Ilya Leoshkevich <iii@linux.ibm.com>
Subject: [PULL 11/31] linux-user: Allow gdbstub to ignore page protection
Date: Tue, 30 Jan 2024 09:01:01 +1000	[thread overview]
Message-ID: <20240129230121.8091-12-richard.henderson@linaro.org> (raw)
In-Reply-To: <20240129230121.8091-1-richard.henderson@linaro.org>

From: Ilya Leoshkevich <iii@linux.ibm.com>

gdbserver ignores page protection by virtue of using /proc/$pid/mem.
Teach qemu gdbstub to do this too. This will not work if /proc is not
mounted; accept this limitation.

One alternative is to temporarily grant the missing PROT_* bit, but
this is inherently racy. Another alternative is self-debugging with
ptrace(POKE), which will break if QEMU itself is being debugged - a
much more severe limitation.

Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com>
Message-Id: <20240129093410.3151-2-iii@linux.ibm.com>
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 cpu-target.c | 78 ++++++++++++++++++++++++++++++++++++++++++----------
 1 file changed, 63 insertions(+), 15 deletions(-)

diff --git a/cpu-target.c b/cpu-target.c
index f6e07c3deb..958d63e882 100644
--- a/cpu-target.c
+++ b/cpu-target.c
@@ -382,6 +382,9 @@ int cpu_memory_rw_debug(CPUState *cpu, vaddr addr,
     vaddr l, page;
     void * p;
     uint8_t *buf = ptr;
+    ssize_t written;
+    int ret = -1;
+    int fd = -1;
 
     while (len > 0) {
         page = addr & TARGET_PAGE_MASK;
@@ -389,30 +392,75 @@ int cpu_memory_rw_debug(CPUState *cpu, vaddr addr,
         if (l > len)
             l = len;
         flags = page_get_flags(page);
-        if (!(flags & PAGE_VALID))
-            return -1;
+        if (!(flags & PAGE_VALID)) {
+            goto out_close;
+        }
         if (is_write) {
-            if (!(flags & PAGE_WRITE))
-                return -1;
+            if (flags & PAGE_WRITE) {
+                /* XXX: this code should not depend on lock_user */
+                p = lock_user(VERIFY_WRITE, addr, l, 0);
+                if (!p) {
+                    goto out_close;
+                }
+                memcpy(p, buf, l);
+                unlock_user(p, addr, l);
+            } else {
+                /* Bypass the host page protection using ptrace. */
+                if (fd == -1) {
+                    fd = open("/proc/self/mem", O_WRONLY);
+                    if (fd == -1) {
+                        goto out;
+                    }
+                }
+                /*
+                 * If there is a TranslationBlock and we weren't bypassing the
+                 * host page protection, the memcpy() above would SEGV,
+                 * ultimately leading to page_unprotect(). So invalidate the
+                 * translations manually. Both invalidation and pwrite() must
+                 * be under mmap_lock() in order to prevent the creation of
+                 * another TranslationBlock in between.
+                 */
+                mmap_lock();
+                tb_invalidate_phys_range(addr, addr + l - 1);
+                written = pwrite(fd, buf, l,
+                                 (off_t)(uintptr_t)g2h_untagged(addr));
+                mmap_unlock();
+                if (written != l) {
+                    goto out_close;
+                }
+            }
+        } else if (flags & PAGE_READ) {
             /* XXX: this code should not depend on lock_user */
-            if (!(p = lock_user(VERIFY_WRITE, addr, l, 0)))
-                return -1;
-            memcpy(p, buf, l);
-            unlock_user(p, addr, l);
-        } else {
-            if (!(flags & PAGE_READ))
-                return -1;
-            /* XXX: this code should not depend on lock_user */
-            if (!(p = lock_user(VERIFY_READ, addr, l, 1)))
-                return -1;
+            p = lock_user(VERIFY_READ, addr, l, 1);
+            if (!p) {
+                goto out_close;
+            }
             memcpy(buf, p, l);
             unlock_user(p, addr, 0);
+        } else {
+            /* Bypass the host page protection using ptrace. */
+            if (fd == -1) {
+                fd = open("/proc/self/mem", O_RDONLY);
+                if (fd == -1) {
+                    goto out;
+                }
+            }
+            if (pread(fd, buf, l,
+                      (off_t)(uintptr_t)g2h_untagged(addr)) != l) {
+                goto out_close;
+            }
         }
         len -= l;
         buf += l;
         addr += l;
     }
-    return 0;
+    ret = 0;
+out_close:
+    if (fd != -1) {
+        close(fd);
+    }
+out:
+    return ret;
 }
 #endif
 
-- 
2.34.1



  parent reply	other threads:[~2024-01-29 23:03 UTC|newest]

Thread overview: 34+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-01-29 23:00 [PULL 00/31] tcg patch queue Richard Henderson
2024-01-29 23:00 ` [PULL 01/31] cpu-exec: simplify jump cache management Richard Henderson
2024-01-29 23:00 ` [PULL 02/31] include/exec: Move vaddr defines to separate file Richard Henderson
2024-01-29 23:00 ` [PULL 03/31] hw/core: Include vaddr.h from cpu.h Richard Henderson
2024-01-29 23:00 ` [PULL 04/31] target: Use vaddr in gen_intermediate_code Richard Henderson
2024-01-29 23:00 ` [PULL 05/31] include/exec: Use vaddr in DisasContextBase for virtual addresses Richard Henderson
2024-01-29 23:00 ` [PULL 06/31] include/exec: typedef abi_ptr to vaddr Richard Henderson
2024-01-29 23:00 ` [PULL 07/31] include/exec: Move PAGE_* macros to common header Richard Henderson
2024-01-29 23:00 ` [PULL 08/31] include/exec: Move cpu_*()/cpu_env() " Richard Henderson
2024-01-29 23:00 ` [PULL 09/31] include/hw/core: Move do_interrupt in TCGCPUOps Richard Henderson
2024-01-29 23:01 ` [PULL 10/31] include/hw/core: Remove i386 conditional on fake_user_interrupt Richard Henderson
2024-01-29 23:01 ` Richard Henderson [this message]
2024-01-29 23:01 ` [PULL 12/31] tests/tcg: Factor out gdbstub test functions Richard Henderson
2024-01-29 23:01 ` [PULL 13/31] tests/tcg: Add the PROT_NONE gdbstub test Richard Henderson
2024-01-31 11:50   ` Ilya Leoshkevich
2024-01-29 23:01 ` [PULL 14/31] accel/tcg/cpu-exec: Use RCU_READ_LOCK_GUARD Richard Henderson
2024-01-29 23:01 ` [PULL 15/31] target: Make qemu_target_page_mask() available for *-user Richard Henderson
2024-01-29 23:01 ` [PULL 16/31] accel/tcg: Make use of qemu_target_page_mask() in perf.c Richard Henderson
2024-01-29 23:01 ` [PULL 17/31] tcg: Make tb_cflags() usable from target-agnostic code Richard Henderson
2024-01-29 23:01 ` [PULL 18/31] accel/tcg: Remove #ifdef TARGET_I386 from perf.c Richard Henderson
2024-01-29 23:01 ` [PULL 19/31] accel/tcg: Move perf and debuginfo support to tcg/ Richard Henderson
2024-01-29 23:01 ` [PULL 20/31] accel/tcg: Rename tcg_ss[] -> tcg_specific_ss[] in meson Richard Henderson
2024-01-29 23:01 ` [PULL 21/31] accel/tcg: Rename tcg_cpus_destroy() -> tcg_cpu_destroy() Richard Henderson
2024-01-29 23:01 ` [PULL 22/31] accel/tcg: Rename tcg_cpus_exec() -> tcg_cpu_exec() Richard Henderson
2024-01-29 23:01 ` [PULL 23/31] accel/tcg: Un-inline icount_exit_request() for clarity Richard Henderson
2024-01-29 23:01 ` [PULL 24/31] include/qemu: Add TCGCPUOps typedef to typedefs.h Richard Henderson
2024-01-29 23:01 ` [PULL 25/31] target/loongarch: Constify loongarch_tcg_ops Richard Henderson
2024-01-29 23:01 ` [PULL 26/31] accel/tcg: Use CPUState.cc instead of CPU_GET_CLASS in cpu-exec.c Richard Henderson
2024-01-29 23:01 ` [PULL 27/31] accel/tcg: Introduce TCGCPUOps::need_replay_interrupt() handler Richard Henderson
2024-01-29 23:01 ` [PULL 28/31] target/i386: Extract x86_need_replay_interrupt() from accel/tcg/ Richard Henderson
2024-01-29 23:01 ` [PULL 29/31] accel/tcg: Inline need_replay_interrupt Richard Henderson
2024-01-29 23:01 ` [PULL 30/31] accel/tcg: Introduce TCGCPUOps::cpu_exec_halt() handler Richard Henderson
2024-01-29 23:01 ` [PULL 31/31] target/i386: Extract x86_cpu_exec_halt() from accel/tcg/ Richard Henderson
2024-01-31 19:52 ` [PULL 00/31] tcg patch queue Peter Maydell

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20240129230121.8091-12-richard.henderson@linaro.org \
    --to=richard.henderson@linaro.org \
    --cc=iii@linux.ibm.com \
    --cc=qemu-devel@nongnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).