mirror of https://github.com/proxmox/mirror_qemu
linux-user: Allow gdbstub to ignore page protection
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>master
parent
fd3f7d24d4
commit
87ab270429
78
cpu-target.c
78
cpu-target.c
|
@ -382,6 +382,9 @@ int cpu_memory_rw_debug(CPUState *cpu, vaddr addr,
|
||||||
vaddr l, page;
|
vaddr l, page;
|
||||||
void * p;
|
void * p;
|
||||||
uint8_t *buf = ptr;
|
uint8_t *buf = ptr;
|
||||||
|
ssize_t written;
|
||||||
|
int ret = -1;
|
||||||
|
int fd = -1;
|
||||||
|
|
||||||
while (len > 0) {
|
while (len > 0) {
|
||||||
page = addr & TARGET_PAGE_MASK;
|
page = addr & TARGET_PAGE_MASK;
|
||||||
|
@ -389,30 +392,75 @@ int cpu_memory_rw_debug(CPUState *cpu, vaddr addr,
|
||||||
if (l > len)
|
if (l > len)
|
||||||
l = len;
|
l = len;
|
||||||
flags = page_get_flags(page);
|
flags = page_get_flags(page);
|
||||||
if (!(flags & PAGE_VALID))
|
if (!(flags & PAGE_VALID)) {
|
||||||
return -1;
|
goto out_close;
|
||||||
|
}
|
||||||
if (is_write) {
|
if (is_write) {
|
||||||
if (!(flags & PAGE_WRITE))
|
if (flags & PAGE_WRITE) {
|
||||||
return -1;
|
/* 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 */
|
/* XXX: this code should not depend on lock_user */
|
||||||
if (!(p = lock_user(VERIFY_WRITE, addr, l, 0)))
|
p = lock_user(VERIFY_READ, addr, l, 1);
|
||||||
return -1;
|
if (!p) {
|
||||||
memcpy(p, buf, l);
|
goto out_close;
|
||||||
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;
|
|
||||||
memcpy(buf, p, l);
|
memcpy(buf, p, l);
|
||||||
unlock_user(p, addr, 0);
|
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;
|
len -= l;
|
||||||
buf += l;
|
buf += l;
|
||||||
addr += l;
|
addr += l;
|
||||||
}
|
}
|
||||||
return 0;
|
ret = 0;
|
||||||
|
out_close:
|
||||||
|
if (fd != -1) {
|
||||||
|
close(fd);
|
||||||
|
}
|
||||||
|
out:
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue