[PATCH 2/5] winedbg: Add support for hardware watchpoints.

Rémi Bernon rbernon at codeweavers.com
Sat Apr 4 04:30:14 CDT 2020


Signed-off-by: Rémi Bernon <rbernon at codeweavers.com>
---
 programs/winedbg/gdbproxy.c | 186 ++++++++++++++++++++++++++++++++++++
 1 file changed, 186 insertions(+)

diff --git a/programs/winedbg/gdbproxy.c b/programs/winedbg/gdbproxy.c
index 8e1267a01832..81fc64898511 100644
--- a/programs/winedbg/gdbproxy.c
+++ b/programs/winedbg/gdbproxy.c
@@ -67,6 +67,17 @@
 
 WINE_DEFAULT_DEBUG_CHANNEL(winedbg);
 
+struct gdb_xpoint
+{
+    struct list entry;
+    int pid;
+    int tid;
+    enum be_xpoint_type type;
+    void *addr;
+    int size;
+    unsigned long value;
+};
+
 struct gdb_context
 {
     /* gdb information */
@@ -86,6 +97,7 @@ struct gdb_context
     /* generic GDB thread information */
     int                         exec_tid; /* tid used in step & continue */
     int                         other_tid; /* tid to be used in any other operation */
+    struct list                 xpoint_list;
     /* current Win32 trap env */
     DEBUG_EVENT                 de;
     DWORD                       de_reply;
@@ -98,6 +110,64 @@ struct gdb_context
     BOOL                        no_ack_mode;
 };
 
+static void gdbctx_delete_xpoint(struct gdb_context *gdbctx, struct dbg_thread *thread,
+                                 dbg_ctx_t *ctx, struct gdb_xpoint *x)
+{
+    struct dbg_process *process = thread->process;
+    struct backend_cpu *cpu = process->be_cpu;
+
+    if (!cpu->remove_Xpoint(process->handle, process->process_io, ctx, x->type, x->addr, x->value, x->size))
+        ERR("%04x:%04x: Couldn't remove breakpoint at:%p/%x type:%d\n", process->pid, thread->tid, x->addr, x->size, x->type);
+
+    list_remove(&x->entry);
+    HeapFree(GetProcessHeap(), 0, x);
+}
+
+static void gdbctx_insert_xpoint(struct gdb_context *gdbctx, struct dbg_thread *thread,
+                                 dbg_ctx_t *ctx, enum be_xpoint_type type, void *addr, int size)
+{
+    struct dbg_process *process = thread->process;
+    struct backend_cpu *cpu = process->be_cpu;
+    struct gdb_xpoint *x;
+    unsigned long value;
+
+    if (!cpu->insert_Xpoint(process->handle, process->process_io, ctx, type, addr, &value, size))
+    {
+        ERR("%04x:%04x: Couldn't insert breakpoint at:%p/%x type:%d\n", process->pid, thread->tid, addr, size, type);
+        return;
+    }
+
+    if (!(x = HeapAlloc(GetProcessHeap(), 0, sizeof(struct gdb_xpoint))))
+    {
+        ERR("%04x:%04x: Couldn't allocate memory for breakpoint at:%p/%x type:%d\n", process->pid, thread->tid, addr, size, type);
+        return;
+    }
+
+    x->pid = process->pid;
+    x->tid = thread->tid;
+    x->type = type;
+    x->addr = addr;
+    x->size = size;
+    x->value = value;
+    list_add_head(&gdbctx->xpoint_list, &x->entry);
+}
+
+static struct gdb_xpoint *gdb_find_xpoint(struct gdb_context *gdbctx, struct dbg_thread *thread,
+                                          enum be_xpoint_type type, void *addr, int size)
+{
+    struct gdb_xpoint *x;
+
+    LIST_FOR_EACH_ENTRY(x, &gdbctx->xpoint_list, struct gdb_xpoint, entry)
+    {
+        if (thread && (x->pid != thread->process->pid || x->tid != thread->tid))
+            continue;
+        if (x->type == type && x->addr == addr && x->size == size)
+            return x;
+    }
+
+    return NULL;
+}
+
 static BOOL tgt_process_gdbproxy_read(HANDLE hProcess, const void* addr,
                                       void* buffer, SIZE_T len, SIZE_T* rlen)
 {
@@ -775,6 +845,34 @@ static inline void packet_reply_register_hex_to(struct gdb_context* gdbctx, dbg_
  * =============================================== *
  */
 
+static void packet_reply_status_xpoints(struct gdb_context* gdbctx, struct dbg_thread *thread,
+                                        dbg_ctx_t *ctx)
+{
+    struct dbg_process *process = thread->process;
+    struct backend_cpu *cpu = process->be_cpu;
+    struct gdb_xpoint *x;
+
+    LIST_FOR_EACH_ENTRY(x, &gdbctx->xpoint_list, struct gdb_xpoint, entry)
+    {
+        if (x->pid != process->pid || x->tid != thread->tid)
+            continue;
+        if (!cpu->is_watchpoint_set(ctx, x->value))
+            continue;
+        if (x->type == be_xpoint_watch_write)
+        {
+            packet_reply_add(gdbctx, "watch:");
+            packet_reply_val(gdbctx, (unsigned long)x->addr, sizeof(x->addr));
+            packet_reply_add(gdbctx, ";");
+        }
+        if (x->type == be_xpoint_watch_read)
+        {
+            packet_reply_add(gdbctx, "rwatch:");
+            packet_reply_val(gdbctx, (unsigned long)x->addr, sizeof(x->addr));
+            packet_reply_add(gdbctx, ";");
+        }
+    }
+}
+
 static enum packet_return packet_reply_status(struct gdb_context* gdbctx)
 {
     struct dbg_process *process = gdbctx->process;
@@ -800,6 +898,7 @@ static enum packet_return packet_reply_status(struct gdb_context* gdbctx)
         packet_reply_add(gdbctx, "thread:");
         packet_reply_val(gdbctx, gdbctx->de.dwThreadId, 4);
         packet_reply_add(gdbctx, ";");
+        packet_reply_status_xpoints(gdbctx, thread, &ctx);
 
         for (i = 0; i < backend->gdb_num_regs; i++)
         {
@@ -924,6 +1023,90 @@ static enum packet_return packet_continue_signal(struct gdb_context* gdbctx)
     return packet_reply_status(gdbctx);
 }
 
+static enum packet_return packet_delete_breakpoint(struct gdb_context* gdbctx)
+{
+    struct dbg_process *process = gdbctx->process;
+    struct dbg_thread *thread;
+    struct backend_cpu *cpu;
+    struct gdb_xpoint *x;
+    dbg_ctx_t ctx;
+    char type;
+    void *addr;
+    int size;
+
+    if (!process) return packet_error;
+    if (!(cpu = process->be_cpu)) return packet_error;
+
+    if (sscanf(gdbctx->in_packet, "%c,%p,%x", &type, &addr, &size) < 3)
+        return packet_error;
+
+    if (type == '0')
+        return packet_error;
+
+    LIST_FOR_EACH_ENTRY(thread, &process->threads, struct dbg_thread, entry)
+    {
+        if (!cpu->get_context(thread->handle, &ctx))
+            continue;
+        if ((type == '1') && (x = gdb_find_xpoint(gdbctx, thread, be_xpoint_watch_exec, addr, size)))
+            gdbctx_delete_xpoint(gdbctx, thread, &ctx, x);
+        if ((type == '2' || type == '4') && (x = gdb_find_xpoint(gdbctx, thread, be_xpoint_watch_read, addr, size)))
+            gdbctx_delete_xpoint(gdbctx, thread, &ctx, x);
+        if ((type == '3' || type == '4') && (x = gdb_find_xpoint(gdbctx, thread, be_xpoint_watch_write, addr, size)))
+            gdbctx_delete_xpoint(gdbctx, thread, &ctx, x);
+        cpu->set_context(thread->handle, &ctx);
+    }
+
+    while ((type == '1') && (x = gdb_find_xpoint(gdbctx, NULL, be_xpoint_watch_exec, addr, size)))
+        gdbctx_delete_xpoint(gdbctx, NULL, NULL, x);
+    while ((type == '2' || type == '4') && (x = gdb_find_xpoint(gdbctx, NULL, be_xpoint_watch_read, addr, size)))
+        gdbctx_delete_xpoint(gdbctx, NULL, NULL, x);
+    while ((type == '3' || type == '4') && (x = gdb_find_xpoint(gdbctx, NULL, be_xpoint_watch_write, addr, size)))
+        gdbctx_delete_xpoint(gdbctx, NULL, NULL, x);
+
+    return packet_ok;
+}
+
+static enum packet_return packet_insert_breakpoint(struct gdb_context* gdbctx)
+{
+    struct dbg_process *process = gdbctx->process;
+    struct dbg_thread *thread;
+    struct backend_cpu *cpu;
+    dbg_ctx_t ctx;
+    char type;
+    void *addr;
+    int size;
+
+    if (!process) return packet_error;
+    if (!(cpu = process->be_cpu)) return packet_error;
+
+    if (memchr(gdbctx->in_packet, ';', gdbctx->in_packet_len))
+    {
+        FIXME("breakpoint commands not supported\n");
+        return packet_error;
+    }
+
+    if (sscanf(gdbctx->in_packet, "%c,%p,%x", &type, &addr, &size) < 3)
+        return packet_error;
+
+    if (type == '0')
+        return packet_error;
+
+    LIST_FOR_EACH_ENTRY(thread, &process->threads, struct dbg_thread, entry)
+    {
+        if (!cpu->get_context(thread->handle, &ctx))
+            continue;
+        if (type == '1')
+            gdbctx_insert_xpoint(gdbctx, thread, &ctx, be_xpoint_watch_exec, addr, size);
+        if (type == '2' || type == '4')
+            gdbctx_insert_xpoint(gdbctx, thread, &ctx, be_xpoint_watch_read, addr, size);
+        if (type == '3' || type == '4')
+            gdbctx_insert_xpoint(gdbctx, thread, &ctx, be_xpoint_watch_write, addr, size);
+        cpu->set_context(thread->handle, &ctx);
+    }
+
+    return packet_ok;
+}
+
 static enum packet_return packet_detach(struct gdb_context* gdbctx)
 {
     detach_debuggee(gdbctx, FALSE);
@@ -1815,6 +1998,8 @@ static struct packet_entry packet_entries[] =
         {'s', packet_step},        
         {'T', packet_thread_alive},
         {'v', packet_verbose},
+        {'z', packet_delete_breakpoint},
+        {'Z', packet_insert_breakpoint},
 };
 
 static BOOL extract_packets(struct gdb_context* gdbctx)
@@ -2069,6 +2254,7 @@ static BOOL gdb_init_context(struct gdb_context* gdbctx, unsigned flags, unsigne
 
     gdbctx->exec_tid = -1;
     gdbctx->other_tid = -1;
+    list_init(&gdbctx->xpoint_list);
     gdbctx->last_sig = 0;
     gdbctx->in_trap = FALSE;
     gdbctx->process = NULL;
-- 
2.26.0




More information about the wine-devel mailing list