Rizin
unix-like reverse engineering framework and cli tools
drx.c
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: 2014 pancake <pancake@nopcode.org>
2 // SPDX-License-Identifier: LGPL-3.0-only
3 
4 #include <rz_types.h>
5 
6 /* -------------------- drx.h ------------------- */
7 #define DRXN 8
8 #define DR_STATUS 6
9 #define DR_CONTROL 7
10 
11 #define DR_LOCAL_ENABLE_SHIFT 0 /* Extra shift to the local enable bit. */
12 #define DR_GLOBAL_ENABLE_SHIFT 1 /* Extra shift to the global enable bit. */
13 #define DR_ENABLE_SIZE 2 /* Two enable bits per debug register. */
14 
15 /* Fields reserved by Intel. This includes the GD (General Detect
16  Enable) flag, which causes a debug exception to be generated when a
17  MOV instruction accesses one of the debug registers.
18 
19  FIXME: My Intel manual says we should use 0xF800, not 0xFC00. */
20 #define DR_CONTROL_RESERVED (0xFC00)
21 
22 #define I386_DR_CONTROL_MASK (~DR_CONTROL_RESERVED)
23 
24 #define DR_LOCAL_SLOWDOWN (0x100)
25 #define DR_GLOBAL_SLOWDOWN (0x200)
26 
27 /* DR7 fields */
28 /* How many bits to skip in DR7 to get to R/W and LEN fields. */
29 #define DR_CONTROL_SHIFT 16
30 /* How many bits in DR7 per R/W and LEN field for each watchpoint. */
31 #define DR_CONTROL_SIZE 4
32 
33 #define DR_RW_EXECUTE (0x0) /* Break on instruction execution. */
34 #define DR_RW_WRITE (0x1) /* Break on data writes. */
35 #define DR_RW_IORW (0x2) /* Break on I/O reads or writes (not supported (2001) */
36 #define DR_RW_READ (0x3) /* Break on data reads or writes. */
37 
38 /* Debug registers' indices. */
39 #define DR_NADDR 4 /* The number of debug address registers. */
40 #define DR_STATUS 6 /* Index of debug status register (DR6). */
41 #define DR_CONTROL 7 /* Index of debug control register (DR7). */
42 
43 // 32 for 32bits and 64 for 64bits
44 #define drxt size_t
45 
46 #define DR_LEN_1 (0 << 2) /* 1-byte region watch or breakpoint. */
47 #define DR_LEN_2 (1 << 2) /* 2-byte region watch. */
48 #define DR_LEN_4 (3 << 2) /* 4-byte region watch. */
49 #define DR_LEN_8 (2 << 2) /* 8-byte region watch (AMD64). */
50 
51 #define I386_DR_CONTROL_MASK (~DR_CONTROL_RESERVED)
52 
53 /* unused */
54 #define I386_DR_VACANT(control, i) \
55  ((control & (3 << (DR_ENABLE_SIZE * (i)))) == 0)
56 /* local/global */
57 #define I386_DR_LOCAL_ENABLE(control, i) \
58  control |= (1 << (DR_LOCAL_ENABLE_SHIFT + DR_ENABLE_SIZE * (i)))
59 #define I386_DR_GLOBAL_ENABLE(control, i) \
60  control |= (1 << (DR_GLOBAL_ENABLE_SHIFT + DR_ENABLE_SIZE * (i)))
61 
62 #define I386_DR_IS_LOCAL_ENABLED(control, i) \
63  (control & (1 << (DR_LOCAL_ENABLE_SHIFT + DR_ENABLE_SIZE * (i))))
64 /* enable/disable */
65 #define I386_DR_IS_ENABLED(control, i) \
66  control &(3 << (DR_ENABLE_SIZE * (i)))
67 
68 #define I386_DR_ENABLE(control, i) \
69  control |= (3 << (DR_ENABLE_SIZE * (i)))
70 #define I386_DR_DISABLE(control, i) \
71  control &= ~(3 << (DR_ENABLE_SIZE * (i)))
72 
73 #define I386_DR_SET_RW_LEN(control, i, rwlen) \
74  do { \
75  control &= ~(0x0f << (DR_CONTROL_SHIFT + DR_CONTROL_SIZE * (i))); \
76  control |= ((rwlen) << (DR_CONTROL_SHIFT + DR_CONTROL_SIZE * (i))); \
77  } while (0)
78 #define I386_DR_GET_RW_LEN(control, i) \
79  ((control >> (DR_CONTROL_SHIFT + DR_CONTROL_SIZE * (i))) & 0x0f)
80 
81 /* ----------------------------- */
82 
83 int drx_set(drxt *drx, int n, ut64 addr, int len, int rwx, int global) {
84  ut32 control = drx[DR_CONTROL];
85  if (n < 0 || n >= DR_NADDR) {
86  eprintf("Invalid DRX index (0-%d)\n", DR_NADDR - 1);
87  return false;
88  }
89  switch (rwx) {
90  case 1: rwx = 0; break;
91  case 2: rwx = 1; break;
92  case 4: rwx = 3; break;
93  default:
94  rwx = 0;
95  }
96  switch (len) {
97  case 1: len = 0; break;
98  case 2: len = 1 << 2; break;
99  case 4: len = 3 << 2; break;
100  case 8: len = 2 << 2; break; // AMD64 only
101  case -1: {
104  drx[DR_CONTROL] = control;
105  drx[n] = 0;
106  return true;
107  }
108  default:
109  eprintf("Invalid DRX length (%d) must be 1, 2, 4, 8 bytes\n", len);
110  return false;
111  }
112  I386_DR_SET_RW_LEN(control, n, len | rwx);
113  if (global) {
115  // control |= DR_GLOBAL_SLOWDOWN;
116  } else {
118  // control |= DR_LOCAL_SLOWDOWN; // XXX: This is wrong
119  }
121  drx[n] = addr;
122  // eprintf ("drx[DR_CONTROL] = %x \n", drx[DR_CONTROL]);
123  drx[DR_CONTROL] = control;
124  // eprintf ("CONTROL = %x\n", control);
125  return true;
126 }
127 
128 ut64 drx_get(drxt *drx, int n, int *rwx, int *len, int *global, int *enabled) {
129  int ret = I386_DR_GET_RW_LEN(drx[DR_CONTROL], n);
130  if (global) {
131  *global = I386_DR_IS_LOCAL_ENABLED(drx[7], n);
132  }
133  if (len) {
134  switch (ret & 0xC) {
135  case DR_LEN_1: *len = 1; break;
136  case DR_LEN_2: *len = 2; break;
137  case DR_LEN_4: *len = 4; break;
138  case DR_LEN_8: *len = 8; break;
139  default: *len = 0; break;
140  }
141  }
142  if (enabled) {
143  *enabled = I386_DR_IS_ENABLED(drx[7], n);
144  }
145  if (rwx) {
146  *rwx = ret & 0x3;
147  }
148  return (ut64)drx[n];
149 }
150 
151 int drx_next(drxt *drx) {
152  int i;
153  for (i = 0; i < 4; i++) {
154  if (!drx[i]) {
155  return i;
156  }
157  }
158  return -1;
159 }
160 
161 int drx_get_at(drxt *drx, ut64 at_addr) {
162  ut64 addr;
163  int i, rwx, len, g, en;
164 
165  for (i = 0; i < 8; i++) {
166  if (i == 4 || i == 5) {
167  continue;
168  }
169  rwx = len = g = en = 0;
170  addr = drx_get(drx, i, &rwx, &len, &g, &en);
171  if (addr == at_addr) {
172  return i;
173  }
174  }
175  return -1;
176 }
177 
178 void drx_list(drxt *drx) {
179  ut64 addr;
180  int i, rwx, len, g, en;
181  for (i = 0; i < 8; i++) {
182  if (i == 4 || i == 5) {
183  continue;
184  }
185  rwx = len = g = en = 0;
186  addr = drx_get(drx, i, &rwx, &len, &g, &en);
187  printf("%c dr%d %c%c 0x%08" PFMT64x " %d\n",
188  en ? '*' : '-', i, g ? 'G' : 'L',
189  (rwx == DR_RW_READ) ? 'r' : (rwx == DR_RW_WRITE) ? 'w'
190  : (rwx == DR_RW_EXECUTE) ? 'x'
191  : (rwx == DR_RW_IORW) ? 'i'
192  : '?',
193  addr, len);
194  }
195 }
196 
197 void drx_init(drxt *r) {
198  memset(r, 0, sizeof(drxt) * (DRXN + 1));
199 }
200 
201 void drx_enable(drxt *r, int n, int enabled) {
202  if (enabled) {
204  } else {
206  }
207 }
208 
210  if (bp->nhwbps < 4) {
212  rz_debug_drx_set(dbg, bp->nhwbps, b->addr, b->size, b->perm, 0);
214  bp->nhwbps++;
215  return true;
216  }
217  return false;
218 }
219 
221  if (bp->nhwbps > 0) {
223  rz_debug_drx_unset(dbg, bp->nhwbps - 1);
225  bp->nhwbps--;
226  }
227  return true;
228 }
229 
230 #if MAIN
231 int main() {
232  drxt regs[DRXN + 1];
233  drx_init(regs);
234  drx_set(regs, 1, 0x8048123, 1, DR_RW_EXECUTE, 0);
235  drx_set(regs, 0, 0x8048123, 4, DR_RW_READ, 1);
236  // drx_enable (regs, 0, true);
237  // drx_enable (regs, 0, false);
238  drx_list(regs);
239 }
240 #endif
size_t len
Definition: 6502dis.c:15
static char * regs[]
Definition: analysis_sh.c:203
lzma_index ** i
Definition: index.h:629
#define r
Definition: crypto_rc6.c:12
_Use_decl_annotations_ int __cdecl printf(const char *const _Format,...)
Definition: cs_driver.c:93
uint32_t ut32
RzDebug * dbg
Definition: desil.c:30
RZ_API int rz_debug_reg_sync(RzDebug *dbg, int type, int write)
Definition: dreg.c:9
#define I386_DR_ENABLE(control, i)
Definition: drx.c:68
#define DR_LEN_2
Definition: drx.c:47
int drx_get_at(drxt *drx, ut64 at_addr)
Definition: drx.c:161
bool drx_add(RzDebug *dbg, RzBreakpoint *bp, RzBreakpointItem *b)
Definition: drx.c:209
#define I386_DR_SET_RW_LEN(control, i, rwlen)
Definition: drx.c:73
#define drxt
Definition: drx.c:44
#define I386_DR_DISABLE(control, i)
Definition: drx.c:70
#define DRXN
Definition: drx.c:7
void drx_enable(drxt *r, int n, int enabled)
Definition: drx.c:201
int drx_next(drxt *drx)
Definition: drx.c:151
#define I386_DR_GET_RW_LEN(control, i)
Definition: drx.c:78
#define I386_DR_LOCAL_ENABLE(control, i)
Definition: drx.c:57
ut64 drx_get(drxt *drx, int n, int *rwx, int *len, int *global, int *enabled)
Definition: drx.c:128
#define DR_RW_EXECUTE
Definition: drx.c:33
void drx_init(drxt *r)
Definition: drx.c:197
void drx_list(drxt *drx)
Definition: drx.c:178
#define DR_NADDR
Definition: drx.c:39
#define I386_DR_GLOBAL_ENABLE(control, i)
Definition: drx.c:59
#define DR_RW_READ
Definition: drx.c:36
#define I386_DR_CONTROL_MASK
Definition: drx.c:51
#define DR_LEN_1
Definition: drx.c:46
bool drx_del(RzDebug *dbg, RzBreakpoint *bp, RzBreakpointItem *b)
Definition: drx.c:220
#define DR_RW_IORW
Definition: drx.c:35
int drx_set(drxt *drx, int n, ut64 addr, int len, int rwx, int global)
Definition: drx.c:83
#define DR_LEN_8
Definition: drx.c:49
#define DR_CONTROL
Definition: drx.c:41
#define I386_DR_IS_ENABLED(control, i)
Definition: drx.c:65
#define DR_LEN_4
Definition: drx.c:48
#define DR_RW_WRITE
Definition: drx.c:34
#define I386_DR_IS_LOCAL_ENABLED(control, i)
Definition: drx.c:62
struct @667 g
return memset(p, 0, total)
RZ_API int rz_debug_drx_set(RzDebug *dbg, int idx, ut64 addr, int len, int rwx, int g)
Definition: debug.c:1668
RZ_API int rz_debug_drx_unset(RzDebug *dbg, int idx)
Definition: debug.c:1675
int n
Definition: mipsasm.c:19
#define eprintf(x, y...)
Definition: rlcc.c:7
int main(int argc, char **argv)
Definition: rz-bb.c:29
@ RZ_REG_TYPE_DRX
Definition: rz_reg.h:22
#define PFMT64x
Definition: rz_types.h:393
#define b(i)
Definition: sha256.c:42
Definition: rz_bp.h:78
int nhwbps
Definition: rz_bp.h:92
control
ut64(WINAPI *w32_GetEnabledXStateFeatures)()
static int addr
Definition: z80asm.c:58