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/>.
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
]);
36 case DR7_TYPE_DATA_WR
:
37 type
= BP_CPU
| BP_MEM_WRITE
;
40 /* No support for I/O watchpoints yet */
42 case DR7_TYPE_DATA_RW
:
43 type
= BP_CPU
| BP_MEM_ACCESS
;
48 err
= cpu_watchpoint_insert(cs
, env
->dr
[index
],
49 hw_breakpoint_len(env
->dr
[7], index
),
50 type
, &env
->cpu_watchpoint
[index
]);
54 env
->cpu_breakpoint
[index
] = NULL
;
58 void hw_breakpoint_remove(CPUX86State
*env
, int index
)
62 if (!env
->cpu_breakpoint
[index
]) {
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
]);
72 case DR7_TYPE_DATA_WR
:
73 case DR7_TYPE_DATA_RW
:
74 cpu_watchpoint_remove_by_ref(cs
, env
->cpu_watchpoint
[index
]);
77 /* No support for I/O watchpoints yet */
82 static bool check_hw_breakpoints(CPUX86State
*env
, bool force_dr6_update
)
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
) {
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
) {
109 if (bp_match
|| wp_match
) {
111 if (hw_breakpoint_enabled(env
->dr
[7], reg
)) {
117 if (hit_enabled
|| force_dr6_update
) {
124 void breakpoint_handler(CPUState
*cs
)
126 X86CPU
*cpu
= X86_CPU(cs
);
127 CPUX86State
*env
= &cpu
->env
;
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
);
136 cpu_resume_from_signal(cs
, NULL
);
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
);
152 void helper_single_step(CPUX86State
*env
)
154 #ifndef CONFIG_USER_ONLY
155 check_hw_breakpoints(env
, true);
156 env
->dr
[6] |= DR6_BS
;
158 raise_exception(env
, EXCP01_DB
);
161 void helper_movl_drN_T0(CPUX86State
*env
, int reg
, target_ulong t0
)
163 #ifndef CONFIG_USER_ONLY
167 hw_breakpoint_remove(env
, reg
);
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
);
175 for (i
= 0; i
< DR7_MAX_BP
; i
++) {
176 hw_breakpoint_insert(env
, i
);