Fixes bug #44349.
Normally, when we hit a breakpoint, we remove it before stopping and add it after continuing. gdb, however, reads the process memory before requesting that the breakpoint be removed, and apparently caches it until the `stepi` instruction is executed; as a result, it thinks that the interrupt byte that is present in the code is an actual interrupt and not a breakpoint, and so tries to step over it as one byte instead of executing the real instruction at that location.
Fix this problem by reporting the real bytes when they are requested, which is what gdb's native backend does as well.
Signed-off-by: Zebediah Figura z.figura12@gmail.com --- programs/winedbg/gdbproxy.c | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-)
diff --git a/programs/winedbg/gdbproxy.c b/programs/winedbg/gdbproxy.c index c02ad3b..7b9a476 100644 --- a/programs/winedbg/gdbproxy.c +++ b/programs/winedbg/gdbproxy.c @@ -1568,6 +1568,28 @@ static enum packet_return packet_thread(struct gdb_context* gdbctx) } }
+static BOOL read_memory(struct gdb_context *gdbctx, char *addr, char *buffer, SIZE_T blk_len, SIZE_T *r) +{ + /* Wrapper around process_io->read() that replaces values displaced by breakpoints. */ + + BOOL ret; + + ret = gdbctx->process->process_io->read(gdbctx->process->handle, addr, buffer, blk_len, r); + if (ret) + { + struct gdb_ctx_Xpoint *xpt; + + for (xpt = &gdbctx->Xpoints[NUM_XPOINT - 1]; xpt >= gdbctx->Xpoints; xpt--) + { + char *xpt_addr = xpt->addr; + + if (xpt->type != -1 && xpt_addr >= addr && xpt_addr < addr + blk_len) + buffer[xpt_addr - addr] = xpt->val; + } + } + return ret; +} + static enum packet_return packet_read_memory(struct gdb_context* gdbctx) { char *addr; @@ -1584,8 +1606,7 @@ static enum packet_return packet_read_memory(struct gdb_context* gdbctx) for (nread = 0; nread < len; nread += r, addr += r) { blk_len = min(sizeof(buffer), len - nread); - if (!gdbctx->process->process_io->read(gdbctx->process->handle, addr, buffer, blk_len, &r) || - r == 0) + if (!read_memory(gdbctx, addr, buffer, blk_len, &r) || r == 0) { /* fail at first address, return error */ if (nread == 0) return packet_reply_error(gdbctx, EFAULT);