[PATCH 7/9] [WineDbg]: implement breakpoint management for x86_64 targets
Eric Pouech
eric.pouech at orange.fr
Mon Dec 14 15:06:00 CST 2009
A+
---
programs/winedbg/be_x86_64.c | 135 ++++++++++++++++++++++++++++++++++++++++--
1 files changed, 128 insertions(+), 7 deletions(-)
diff --git a/programs/winedbg/be_x86_64.c b/programs/winedbg/be_x86_64.c
index ed5cdf2..ffd41d4 100644
--- a/programs/winedbg/be_x86_64.c
+++ b/programs/winedbg/be_x86_64.c
@@ -2,6 +2,7 @@
* Debugger x86_64 specific functions
*
* Copyright 2004 Vincent Béron
+ * 2009 Eric Pouech
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -19,6 +20,9 @@
*/
#include "debugger.h"
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(winedbg);
#if defined(__x86_64__)
@@ -187,31 +191,148 @@ static void be_x86_64_disasm_one_insn(ADDRESS64* addr, int display)
dbg_printf("Disasm NIY\n");
}
+#define DR7_CONTROL_SHIFT 16
+#define DR7_CONTROL_SIZE 4
+
+#define DR7_RW_EXECUTE (0x0)
+#define DR7_RW_WRITE (0x1)
+#define DR7_RW_READ (0x3)
+
+#define DR7_LEN_1 (0x0)
+#define DR7_LEN_2 (0x4)
+#define DR7_LEN_4 (0xC)
+
+#define DR7_LOCAL_ENABLE_SHIFT 0
+#define DR7_GLOBAL_ENABLE_SHIFT 1
+#define DR7_ENABLE_SIZE 2
+
+#define DR7_LOCAL_ENABLE_MASK (0x55)
+#define DR7_GLOBAL_ENABLE_MASK (0xAA)
+
+#define DR7_CONTROL_RESERVED (0xFC00)
+#define DR7_LOCAL_SLOWDOWN (0x100)
+#define DR7_GLOBAL_SLOWDOWN (0x200)
+
+#define DR7_ENABLE_MASK(dr) (1<<(DR7_LOCAL_ENABLE_SHIFT+DR7_ENABLE_SIZE*(dr)))
+#define IS_DR7_SET(ctrl,dr) ((ctrl)&DR7_ENABLE_MASK(dr))
+
+static inline int be_x86_64_get_unused_DR(CONTEXT* ctx, DWORD64** r)
+{
+ if (!IS_DR7_SET(ctx->Dr7, 0))
+ {
+ *r = &ctx->Dr0;
+ return 0;
+ }
+ if (!IS_DR7_SET(ctx->Dr7, 1))
+ {
+ *r = &ctx->Dr1;
+ return 1;
+ }
+ if (!IS_DR7_SET(ctx->Dr7, 2))
+ {
+ *r = &ctx->Dr2;
+ return 2;
+ }
+ if (!IS_DR7_SET(ctx->Dr7, 3))
+ {
+ *r = &ctx->Dr3;
+ return 3;
+ }
+ dbg_printf("All hardware registers have been used\n");
+
+ return -1;
+}
+
static unsigned be_x86_64_insert_Xpoint(HANDLE hProcess, const struct be_process_io* pio,
CONTEXT* ctx, enum be_xpoint_type type,
void* addr, unsigned long* val, unsigned size)
{
- dbg_printf("not done insert_Xpoint\n");
- return 0;
+ unsigned char ch;
+ SIZE_T sz;
+ DWORD64 *pr;
+ int reg;
+ unsigned long bits;
+
+ switch (type)
+ {
+ case be_xpoint_break:
+ if (size != 0) return 0;
+ if (!pio->read(hProcess, addr, &ch, 1, &sz) || sz != 1) return 0;
+ *val = ch;
+ ch = 0xcc;
+ if (!pio->write(hProcess, addr, &ch, 1, &sz) || sz != 1) return 0;
+ break;
+ case be_xpoint_watch_exec:
+ bits = DR7_RW_EXECUTE;
+ goto hw_bp;
+ case be_xpoint_watch_read:
+ bits = DR7_RW_READ;
+ goto hw_bp;
+ case be_xpoint_watch_write:
+ bits = DR7_RW_WRITE;
+ hw_bp:
+ if ((reg = be_x86_64_get_unused_DR(ctx, &pr)) == -1) return 0;
+ *pr = (DWORD64)addr;
+ if (type != be_xpoint_watch_exec) switch (size)
+ {
+ case 4: bits |= DR7_LEN_4; break;
+ case 2: bits |= DR7_LEN_2; break;
+ case 1: bits |= DR7_LEN_1; break;
+ default: return 0;
+ }
+ *val = reg;
+ /* clear old values */
+ ctx->Dr7 &= ~(0x0F << (DR7_CONTROL_SHIFT + DR7_CONTROL_SIZE * reg));
+ /* set the correct ones */
+ ctx->Dr7 |= bits << (DR7_CONTROL_SHIFT + DR7_CONTROL_SIZE * reg);
+ ctx->Dr7 |= DR7_ENABLE_MASK(reg) | DR7_LOCAL_SLOWDOWN;
+ break;
+ default:
+ dbg_printf("Unknown bp type %c\n", type);
+ return 0;
+ }
+ return 1;
}
static unsigned be_x86_64_remove_Xpoint(HANDLE hProcess, const struct be_process_io* pio,
CONTEXT* ctx, enum be_xpoint_type type,
void* addr, unsigned long val, unsigned size)
{
- dbg_printf("not done remove_Xpoint\n");
- return FALSE;
+ SIZE_T sz;
+ unsigned char ch;
+
+ switch (type)
+ {
+ case be_xpoint_break:
+ if (size != 0) return 0;
+ if (!pio->read(hProcess, addr, &ch, 1, &sz) || sz != 1) return 0;
+ if (ch != (unsigned char)0xCC)
+ WINE_FIXME("Cannot get back %02x instead of 0xCC at %08lx\n",
+ ch, (unsigned long)addr);
+ ch = (unsigned char)val;
+ if (!pio->write(hProcess, addr, &ch, 1, &sz) || sz != 1) return 0;
+ break;
+ case be_xpoint_watch_exec:
+ case be_xpoint_watch_read:
+ case be_xpoint_watch_write:
+ /* simply disable the entry */
+ ctx->Dr7 &= ~DR7_ENABLE_MASK(val);
+ break;
+ default:
+ dbg_printf("Unknown bp type %c\n", type);
+ return 0;
+ }
+ return 1;
}
static unsigned be_x86_64_is_watchpoint_set(const CONTEXT* ctx, unsigned idx)
{
- dbg_printf("not done is_watchpoint_set\n");
- return FALSE;
+ return ctx->Dr6 & (1 << idx);
}
static void be_x86_64_clear_watchpoint(CONTEXT* ctx, unsigned idx)
{
- dbg_printf("not done clear_watchpoint\n");
+ ctx->Dr6 &= ~(1 << idx);
}
static int be_x86_64_adjust_pc_for_break(CONTEXT* ctx, BOOL way)
More information about the wine-patches
mailing list