-#define CONTROL D_REGS[DR_CONTROL]
-#define STATUS D_REGS[DR_STATUS]
-
-#define IS_REG_FREE(index) \
- (!(CONTROL & (3 << (DR_ENABLE_SIZE * (index)))))
-
-#define LOCAL_ENABLE_REG(index) \
- (CONTROL |= (1 << (DR_LOCAL_ENABLE_SHIFT + DR_ENABLE_SIZE * (index))))
-
-#define GLOBAL_ENABLE_REG(index) \
- (CONTROL |= (1 << (DR_GLOBAL_ENABLE_SHIFT + DR_ENABLE_SIZE * (index))))
-
-#define DISABLE_REG(index) \
- (CONTROL &= ~(3 << (DR_ENABLE_SIZE * (index))))
-
-#define SET_LOCAL_EXACT() \
- (CONTROL |= DR_LOCAL_SLOWDOWN)
-
-#define SET_GLOBAL_EXACT() \
- (CONTROL |= DR_GLOBAL_SLOWDOWN)
-
-#define RESET_LOCAL_EXACT() \
- (CONTROL &= ~(DR_LOCAL_SLOWDOWN))
-
-#define RESET_GLOBAL_EXACT() \
- (CONTROL &= ~(DR_GLOBAL_SLOWDOWN))
-
-#define SET_BREAK(index,address) \
- do {\
- CONTROL &= ~(DR_CONTROL_MASK << (DR_CONTROL_SHIFT + DR_CONTROL_SIZE * (index)));\
- D_REGS[index] = address;\
- dr_ref_count[index]++;\
- } while(0)
-
-#define SET_WATCH(index,address,rw,len) \
- do {\
- SET_BREAK(index,address);\
- CONTROL |= ((len)|(rw)) << (DR_CONTROL_SHIFT + DR_CONTROL_SIZE * (index));\
- } while (0)
-
-#define IS_WATCH(index) \
- (CONTROL & (DR_CONTROL_MASK << (DR_CONTROL_SHIFT + DR_CONTROL_SIZE*(index))))
-
-#define WATCH_HIT(index) ((STATUS & (1 << (index))) && IS_WATCH(index))
-
-#define DR_DEF(index) \
- ((CONTROL >> (DR_CONTROL_SHIFT + DR_CONTROL_SIZE * (index))) & 0x0f)
-
-
-#if 0 /* use debugging macro */
-#define SHOW_DR(text,len) \
-do { \
- if (!getenv ("GDB_SHOW_DR")) break; \
- fprintf(stderr,"%08x %08x ",edi.dr[7],edi.dr[6]); \
- fprintf(stderr,"%08x %d %08x %d ", \
- edi.dr[0],dr_ref_count[0],edi.dr[1],dr_ref_count[1]); \
- fprintf(stderr,"%08x %d %08x %d ", \
- edi.dr[2],dr_ref_count[2],edi.dr[3],dr_ref_count[3]); \
- fprintf(stderr,(len)?"(%s:%d)\n":"(%s)\n",#text,len); \
-} while (0)
-#else
-#define SHOW_DR(text,len) do {} while (0)
-#endif
-
-static void
-cleanup_dregs (void)
-{
- int i;
-
- CONTROL = 0;
- STATUS = 0;
- for (i = 0; i < 4; i++)
- {
- D_REGS[i] = 0;
- dr_ref_count[i] = 0;
- }
-}
-
-/* Insert a watchpoint. */
-
-int
-go32_insert_watchpoint (int pid ATTRIBUTE_UNUSED, CORE_ADDR addr,
- int len, int rw)
-{
- int ret = go32_insert_aligned_watchpoint (addr, addr, len, rw);
-
- SHOW_DR (insert_watch, len);
- return ret;
-}
-
-static int
-go32_insert_aligned_watchpoint (CORE_ADDR waddr, CORE_ADDR addr,
- int len, int rw)
-{
- int i;
- int read_write_bits, len_bits;
-
- /* Values of rw: 0 - write, 1 - read, 2 - access (read and write).
- However, x86 doesn't support read-only data breakpoints. */
- read_write_bits = rw ? DR_RW_READWRITE : DR_RW_WRITE;
-
- switch (len)
- {
- case 4:
- len_bits = DR_LEN_4;
- break;
- case 2:
- len_bits = DR_LEN_2;
- break;
- case 1:
- len_bits = DR_LEN_1;
- break;
- default:
- /* The debug registers only have 2 bits for the length, so
- so this value will always fail the loop below. */
- len_bits = 0x10;
- }
-
- /* Look for an occupied debug register with the same address and the
- same RW and LEN definitions. If we find one, we can use it for
- this watchpoint as well (and save a register). */
- for (i = 0; i < 4; i++)
- {
- if (!IS_REG_FREE (i) && D_REGS[i] == addr
- && DR_DEF (i) == (unsigned)(len_bits | read_write_bits))
- {
- dr_ref_count[i]++;
- return 0;
- }
- }
-
- /* Look for a free debug register. */
- for (i = 0; i <= 3; i++)
- {
- if (IS_REG_FREE (i))
- break;
- }
-
- /* No more debug registers! */
- if (i > 3)
- return -1;
-
- if (len == 2)
- {
- if (addr % 2)
- return go32_handle_nonaligned_watchpoint (wp_insert, waddr, addr,
- len, rw);
- }
- else if (len == 4)
- {
- if (addr % 4)
- return go32_handle_nonaligned_watchpoint (wp_insert, waddr, addr,
- len, rw);
- }
- else if (len != 1)
- return go32_handle_nonaligned_watchpoint (wp_insert, waddr, addr, len, rw);
-
- SET_WATCH (i, addr, read_write_bits, len_bits);
- LOCAL_ENABLE_REG (i);
- SET_LOCAL_EXACT ();
- SET_GLOBAL_EXACT ();
- return 0;
-}
-
-static int
-go32_handle_nonaligned_watchpoint (wp_op what, CORE_ADDR waddr, CORE_ADDR addr,
- int len, int rw)
-{
- int align;
- int size;
- int rv = 0, status = 0;
-
- static int size_try_array[4][4] =
- {
- { 1, 1, 1, 1 }, /* trying size one */
- { 2, 1, 2, 1 }, /* trying size two */
- { 2, 1, 2, 1 }, /* trying size three */
- { 4, 1, 2, 1 } /* trying size four */
- };
-
- while (len > 0)
- {
- align = addr % 4;
- /* Four is the maximum length a 386 debug register can watch. */
- size = size_try_array[len > 4 ? 3 : len - 1][align];
- if (what == wp_insert)
- status = go32_insert_aligned_watchpoint (waddr, addr, size, rw);
- else if (what == wp_remove)
- status = go32_remove_aligned_watchpoint (waddr, addr, size, rw);
- else if (what == wp_count)
- rv++;
- else
- status = EINVAL;
- /* We keep the loop going even after a failure, because some of
- the other aligned watchpoints might still succeed, e.g. if
- they watch addresses that are already watched, and thus just
- increment the reference counts of occupied debug registers.
- If we break out of the loop too early, we could cause those
- addresses watched by other watchpoints to be disabled when
- GDB reacts to our failure to insert this watchpoint and tries
- to remove it. */
- if (status)
- rv = status;
- addr += size;
- len -= size;
- }
- return rv;
-}
-
-/* Remove a watchpoint. */