block: Add "drained begin/end" for transactional external snapshot
[qemu/ar7.git] / target-i386 / bpt_helper.c
blobc071c24782ea1ce837864d9d03e039256baeb73f
1 /*
2 * i386 breakpoint helpers
4 * Copyright (c) 2003 Fabrice Bellard
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
20 #include "cpu.h"
21 #include "exec/helper-proto.h"
24 void hw_breakpoint_insert(CPUX86State *env, int index)
26 CPUState *cs = CPU(x86_env_get_cpu(env));
27 int type = 0, err = 0;
29 switch (hw_breakpoint_type(env->dr[7], index)) {
30 case DR7_TYPE_BP_INST:
31 if (hw_breakpoint_enabled(env->dr[7], index)) {
32 err = cpu_breakpoint_insert(cs, env->dr[index], BP_CPU,
33 &env->cpu_breakpoint[index]);
35 break;
36 case DR7_TYPE_DATA_WR:
37 type = BP_CPU | BP_MEM_WRITE;
38 break;
39 case DR7_TYPE_IO_RW:
40 /* No support for I/O watchpoints yet */
41 break;
42 case DR7_TYPE_DATA_RW:
43 type = BP_CPU | BP_MEM_ACCESS;
44 break;
47 if (type != 0) {
48 err = cpu_watchpoint_insert(cs, env->dr[index],
49 hw_breakpoint_len(env->dr[7], index),
50 type, &env->cpu_watchpoint[index]);
53 if (err) {
54 env->cpu_breakpoint[index] = NULL;
58 void hw_breakpoint_remove(CPUX86State *env, int index)
60 CPUState *cs;
62 if (!env->cpu_breakpoint[index]) {
63 return;
65 cs = CPU(x86_env_get_cpu(env));
66 switch (hw_breakpoint_type(env->dr[7], index)) {
67 case DR7_TYPE_BP_INST:
68 if (hw_breakpoint_enabled(env->dr[7], index)) {
69 cpu_breakpoint_remove_by_ref(cs, env->cpu_breakpoint[index]);
71 break;
72 case DR7_TYPE_DATA_WR:
73 case DR7_TYPE_DATA_RW:
74 cpu_watchpoint_remove_by_ref(cs, env->cpu_watchpoint[index]);
75 break;
76 case DR7_TYPE_IO_RW:
77 /* No support for I/O watchpoints yet */
78 break;
82 static bool check_hw_breakpoints(CPUX86State *env, bool force_dr6_update)
84 target_ulong dr6;
85 int reg;
86 bool hit_enabled = false;
88 dr6 = env->dr[6] & ~0xf;
89 for (reg = 0; reg < DR7_MAX_BP; reg++) {
90 bool bp_match = false;
91 bool wp_match = false;
93 switch (hw_breakpoint_type(env->dr[7], reg)) {
94 case DR7_TYPE_BP_INST:
95 if (env->dr[reg] == env->eip) {
96 bp_match = true;
98 break;
99 case DR7_TYPE_DATA_WR:
100 case DR7_TYPE_DATA_RW:
101 if (env->cpu_watchpoint[reg] &&
102 env->cpu_watchpoint[reg]->flags & BP_WATCHPOINT_HIT) {
103 wp_match = true;
105 break;
106 case DR7_TYPE_IO_RW:
107 break;
109 if (bp_match || wp_match) {
110 dr6 |= 1 << reg;
111 if (hw_breakpoint_enabled(env->dr[7], reg)) {
112 hit_enabled = true;
117 if (hit_enabled || force_dr6_update) {
118 env->dr[6] = dr6;
121 return hit_enabled;
124 void breakpoint_handler(CPUState *cs)
126 X86CPU *cpu = X86_CPU(cs);
127 CPUX86State *env = &cpu->env;
128 CPUBreakpoint *bp;
130 if (cs->watchpoint_hit) {
131 if (cs->watchpoint_hit->flags & BP_CPU) {
132 cs->watchpoint_hit = NULL;
133 if (check_hw_breakpoints(env, false)) {
134 raise_exception(env, EXCP01_DB);
135 } else {
136 cpu_resume_from_signal(cs, NULL);
139 } else {
140 QTAILQ_FOREACH(bp, &cs->breakpoints, entry) {
141 if (bp->pc == env->eip) {
142 if (bp->flags & BP_CPU) {
143 check_hw_breakpoints(env, true);
144 raise_exception(env, EXCP01_DB);
146 break;
152 void helper_single_step(CPUX86State *env)
154 #ifndef CONFIG_USER_ONLY
155 check_hw_breakpoints(env, true);
156 env->dr[6] |= DR6_BS;
157 #endif
158 raise_exception(env, EXCP01_DB);
161 void helper_movl_drN_T0(CPUX86State *env, int reg, target_ulong t0)
163 #ifndef CONFIG_USER_ONLY
164 int i;
166 if (reg < 4) {
167 hw_breakpoint_remove(env, reg);
168 env->dr[reg] = t0;
169 hw_breakpoint_insert(env, reg);
170 } else if (reg == 7) {
171 for (i = 0; i < DR7_MAX_BP; i++) {
172 hw_breakpoint_remove(env, i);
174 env->dr[7] = t0;
175 for (i = 0; i < DR7_MAX_BP; i++) {
176 hw_breakpoint_insert(env, i);
178 } else {
179 env->dr[reg] = t0;
181 #endif