]> Git Repo - qemu.git/blob - target-i386/bpt_helper.c
Merge remote-tracking branch 'remotes/ehabkost/tags/x86-pull-request' into staging
[qemu.git] / target-i386 / bpt_helper.c
1 /*
2  *  i386 breakpoint helpers
3  *
4  *  Copyright (c) 2003 Fabrice Bellard
5  *
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.
10  *
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.
15  *
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/>.
18  */
19
20 #include "cpu.h"
21 #include "exec/helper-proto.h"
22
23
24 void hw_breakpoint_insert(CPUX86State *env, int index)
25 {
26     CPUState *cs = CPU(x86_env_get_cpu(env));
27     int type = 0, err = 0;
28
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]);
34         }
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;
45     }
46
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]);
51     }
52
53     if (err) {
54         env->cpu_breakpoint[index] = NULL;
55     }
56 }
57
58 void hw_breakpoint_remove(CPUX86State *env, int index)
59 {
60     CPUState *cs;
61
62     if (!env->cpu_breakpoint[index]) {
63         return;
64     }
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]);
70         }
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;
79     }
80 }
81
82 static bool check_hw_breakpoints(CPUX86State *env, bool force_dr6_update)
83 {
84     target_ulong dr6;
85     int reg;
86     bool hit_enabled = false;
87
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;
92
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;
97             }
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;
104             }
105             break;
106         case DR7_TYPE_IO_RW:
107             break;
108         }
109         if (bp_match || wp_match) {
110             dr6 |= 1 << reg;
111             if (hw_breakpoint_enabled(env->dr[7], reg)) {
112                 hit_enabled = true;
113             }
114         }
115     }
116
117     if (hit_enabled || force_dr6_update) {
118         env->dr[6] = dr6;
119     }
120
121     return hit_enabled;
122 }
123
124 void breakpoint_handler(CPUState *cs)
125 {
126     X86CPU *cpu = X86_CPU(cs);
127     CPUX86State *env = &cpu->env;
128     CPUBreakpoint *bp;
129
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);
137             }
138         }
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);
145                 }
146                 break;
147             }
148         }
149     }
150 }
151
152 void helper_single_step(CPUX86State *env)
153 {
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);
159 }
160
161 void helper_movl_drN_T0(CPUX86State *env, int reg, target_ulong t0)
162 {
163 #ifndef CONFIG_USER_ONLY
164     int i;
165
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);
173         }
174         env->dr[7] = t0;
175         for (i = 0; i < DR7_MAX_BP; i++) {
176             hw_breakpoint_insert(env, i);
177         }
178     } else {
179         env->dr[reg] = t0;
180     }
181 #endif
182 }
This page took 0.032369 seconds and 4 git commands to generate.