radare2/libr/debug/p/drx.c
pancake ee39ba239a * Add 'FS' #define for w32 and *nix
* Add support for thumb mode ARM disassembler
  - Workaround a warning in r_vm for arm-16
* More work on drx.c, but still not integrated
2010-10-04 00:42:11 +02:00

176 lines
5.0 KiB
C

#include <r_types.h>
/* -------------------- drx.h ------------------- */
#define DRXN 7
#define DR_STATUS 6
#define DR_CONTROL 7
#define DR_LOCAL_ENABLE_SHIFT 0 /* Extra shift to the local enable bit. */
#define DR_GLOBAL_ENABLE_SHIFT 1 /* Extra shift to the global enable bit. */
#define DR_ENABLE_SIZE 2 /* Two enable bits per debug register. */
/* Fields reserved by Intel. This includes the GD (General Detect
Enable) flag, which causes a debug exception to be generated when a
MOV instruction accesses one of the debug registers.
FIXME: My Intel manual says we should use 0xF800, not 0xFC00. */
#define DR_CONTROL_RESERVED (0xFC00)
#define I386_DR_CONTROL_MASK (~DR_CONTROL_RESERVED)
#define DR_LOCAL_SLOWDOWN (0x100)
#define DR_GLOBAL_SLOWDOWN (0x200)
/* DR7 fields */
/* How many bits to skip in DR7 to get to R/W and LEN fields. */
#define DR_CONTROL_SHIFT 16
/* How many bits in DR7 per R/W and LEN field for each watchpoint. */
#define DR_CONTROL_SIZE 4
#define DR_RW_EXECUTE (0x0) /* Break on instruction execution. */
#define DR_RW_WRITE (0x1) /* Break on data writes. */
#define DR_RW_IORW (0x2) /* Break on I/O reads or writes (not supported (2001) */
#define DR_RW_READ (0x3) /* Break on data reads or writes. */
/* Debug registers' indices. */
#define DR_NADDR 4 /* The number of debug address registers. */
#define DR_STATUS 6 /* Index of debug status register (DR6). */
#define DR_CONTROL 7 /* Index of debug control register (DR7). */
// is ut64 on 64 bitz ?
//#define drxt ut64
#define drxt ut32
#define DR_LEN_1 (0<<2) /* 1-byte region watch or breakpoint. */
#define DR_LEN_2 (1<<2) /* 2-byte region watch. */
#define DR_LEN_4 (3<<2) /* 4-byte region watch. */
#define DR_LEN_8 (2<<2) /* 8-byte region watch (AMD64). */
#define I386_DR_CONTROL_MASK (~DR_CONTROL_RESERVED)
/* unused */
#define I386_DR_VACANT(control, i) \
((control & (3 << (DR_ENABLE_SIZE * (i)))) == 0)
/* local/global */
#define I386_DR_LOCAL_ENABLE(control, i) \
control |= (1 << (DR_LOCAL_ENABLE_SHIFT + DR_ENABLE_SIZE * (i)))
#define I386_DR_GLOBAL_ENABLE(control, i) \
control |= (1 << (DR_GLOBAL_ENABLE_SHIFT + DR_ENABLE_SIZE * (i)))
#define I386_DR_IS_LOCAL_ENABLED(control, i) \
(control & (1 << (DR_LOCAL_ENABLE_SHIFT + DR_ENABLE_SIZE * (i))))
/* enable/disable */
#define I386_DR_IS_ENABLED(control, i) \
control & (3 << (DR_ENABLE_SIZE * (i)))
#define I386_DR_ENABLE(control, i) \
control |= (3 << (DR_ENABLE_SIZE * (i)))
#define I386_DR_DISABLE(control, i) \
control &= ~(3 << (DR_ENABLE_SIZE * (i)))
#define I386_DR_SET_RW_LEN(control, i,rwlen) \
do { \
control &= ~(0x0f << (DR_CONTROL_SHIFT+DR_CONTROL_SIZE*(i))); \
control |= ((rwlen) << (DR_CONTROL_SHIFT+DR_CONTROL_SIZE*(i))); \
} while (0)
#define I386_DR_GET_RW_LEN(control, i) \
((control >> (DR_CONTROL_SHIFT + DR_CONTROL_SIZE * (i))) & 0x0f)
/* ----------------------------- */
int drx_set(drxt *drx, int n, ut64 addr, int len, int rwx, int global) {
ut32 control = drx[DR_CONTROL];
if (n<0 || n>4) {
eprintf ("Invalid DRX index (0-4)\n");
return R_FALSE;
}
if (rwx<0 || rwx>3)
rwx = 0; // defaults to X
switch (len) {
case 1:
len = 0;
break;
case 2:
len = 1<<2;
break;
case 4:
len = 3<<2;
break;
case 8:
len = 2<<2; // AMD64 only
break;
default:
eprintf ("Invalid DRX length\n");
return R_FALSE;
}
I386_DR_SET_RW_LEN (control, n, len|rwx);
if (global) {
I386_DR_GLOBAL_ENABLE (control, n);
control |= DR_GLOBAL_SLOWDOWN;
} else {
I386_DR_LOCAL_ENABLE (control, n);
control |= DR_LOCAL_SLOWDOWN; // XXX: This is wrong
}
control &= I386_DR_CONTROL_MASK;
drx[n] = addr;
drx[DR_CONTROL] = control;
}
ut64 drx_get(drxt *drx, int n, int *rwx, int *len, int *global, int *enabled) {
int ret = I386_DR_GET_RW_LEN (drx[DR_CONTROL], n);
if (global) *global = I386_DR_IS_LOCAL_ENABLED (drx[7], n);
if (len) switch ((ret&0x3)<<2) {
case DR_LEN_1: *len = 1; break;
case DR_LEN_2: *len = 2; break;
case DR_LEN_4: *len = 4; break;
case DR_LEN_8: *len = 8; break;
}
if (enabled) *enabled = I386_DR_IS_ENABLED (drx[7], n);
if (rwx) *rwx = ret & 0x3;
return (ut64)drx[n];
}
int drx_next(drxt *drx) {
int i;
for(i=0; i<4; i++)
if (!drx[i])
return i;
return -1;
}
void drx_list(drxt *drx) {
ut64 addr;
int i, rwx, len, g, en;
for(i=0; i<4; i++) {
addr = drx_get (drx, i, &rwx, &len, &g, &en);
printf ("%c dr%d %c%c 0x%08llx %d\n",
en?'*':'-', i, g?'g':'l',
(rwx==DR_RW_READ)?'r':
(rwx==DR_RW_WRITE)?'w':
(rwx==DR_RW_EXECUTE)?'x':
(rwx==DR_RW_IORW)?'i':'?',
addr, len);
}
}
void drx_init(drxt *r) {
memset (r, 0, sizeof (drxt)*(DRXN+1));
}
void drx_enable(drxt *r, int n, int enabled) {
if (enabled) I386_DR_ENABLE (r[DR_CONTROL], n);
else I386_DR_DISABLE (r[DR_CONTROL], n);
}
#if MAIN
int main() {
drxt regs[DRXN];
drx_init (regs);
drx_set (regs, 1, 0x8048123, 1, DR_RW_EXECUTE, 0);
drx_set (regs, 0, 0x8048123, 4, DR_RW_READ, 1);
//drx_enable (regs, 0, R_TRUE);
// drx_enable (regs, 0, R_FALSE);
drx_list (regs);
}
#endif