On 1/10/24 06:39, Ilya Leoshkevich wrote:
On Wed, 2024-01-10 at 04:42 +1100, Richard Henderson wrote:
On 1/9/24 10:34, Ilya Leoshkevich wrote:
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.

Signed-off-by: Ilya Leoshkevich <i...@linux.ibm.com>
---
   cpu-target.c | 55 ++++++++++++++++++++++++++++++++++++++---------
-----
   1 file changed, 40 insertions(+), 15 deletions(-)

diff --git a/cpu-target.c b/cpu-target.c
index 5eecd7ea2d7..69e97f78980 100644
--- a/cpu-target.c
+++ b/cpu-target.c
@@ -406,6 +406,15 @@ int cpu_memory_rw_debug(CPUState *cpu, vaddr
addr,
       vaddr l, page;
       void * p;
       uint8_t *buf = ptr;
+    int ret = -1;
+    int mem_fd;
+
+    /*
+     * Try ptrace first. If /proc is not mounted or if there is a
different
+     * problem, fall back to the manual page access. Note that,
unlike ptrace,
+     * it will not be able to ignore the protection bits.
+     */
+    mem_fd = open("/proc/self/mem", is_write ? O_WRONLY :
O_RDONLY);

Surely this is the unlikely fallback, and you don't need to open
unless the page is
otherwise inaccessible.

Ok, I can move this under (flags & PAGE_*) checks.

I see no handling for writes to pages that contain TranslationBlocks.

Sorry, I completely missed that. I'm currently experimenting with the
following:

        /*
         * If there is a TranslationBlock and we weren't bypassing
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_page(page);
        written = pwrite(fd, buf, l, (off_t)g2h_untagged(addr));

I would use here tb_invalidate_phys_range(addr, addr + l - 1),
but otherwise, it looks good.


r~

        mmap_unlock();

Does that look okay?

[...]


Reply via email to