]>
Commit | Line | Data |
---|---|---|
b9d580a4 SG |
1 | /* Simulator breakpoint support. |
2 | Copyright (C) 1997 Free Software Foundation, Inc. | |
3 | Contributed by Cygnus Support. | |
4 | ||
5 | This file is part of GDB, the GNU debugger. | |
6 | ||
7 | This program is free software; you can redistribute it and/or modify | |
8 | it under the terms of the GNU General Public License as published by | |
9 | the Free Software Foundation; either version 2, or (at your option) | |
10 | any later version. | |
11 | ||
12 | This program is distributed in the hope that it will be useful, | |
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | GNU General Public License for more details. | |
16 | ||
17 | You should have received a copy of the GNU General Public License along | |
18 | with this program; if not, write to the Free Software Foundation, Inc., | |
19 | 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ | |
20 | ||
21 | #include <stdio.h> | |
b9d580a4 SG |
22 | |
23 | #include "sim-main.h" | |
24 | #include "sim-assert.h" | |
25 | #include "sim-break.h" | |
26 | ||
27 | #ifndef SIM_BREAKPOINT | |
28 | #define SIM_BREAKPOINT {0x00} | |
29 | #define SIM_BREAKPOINT_SIZE (1) | |
30 | #endif | |
31 | ||
32 | struct | |
33 | sim_breakpoint | |
34 | { | |
35 | struct sim_breakpoint *next; | |
36 | SIM_ADDR addr; /* Address of this breakpoint */ | |
37 | int flags; | |
38 | unsigned char loc_contents[SIM_BREAKPOINT_SIZE]; /* Contents of addr while | |
39 | BP is enabled */ | |
40 | }; | |
41 | ||
42 | #define SIM_BREAK_INSERTED 0x1 /* Breakpoint has been inserted */ | |
43 | #define SIM_BREAK_DISABLED 0x2 /* Breakpoint is disabled */ | |
44 | ||
45 | static unsigned char sim_breakpoint [] = SIM_BREAKPOINT; | |
46 | ||
47 | static void insert_breakpoint PARAMS ((SIM_DESC sd, | |
48 | struct sim_breakpoint *bp)); | |
49 | static void remove_breakpoint PARAMS ((SIM_DESC sd, | |
50 | struct sim_breakpoint *bp)); | |
51 | static SIM_RC resume_handler PARAMS ((SIM_DESC sd)); | |
52 | static SIM_RC suspend_handler PARAMS ((SIM_DESC sd)); | |
53 | ||
54 | ||
eefc25e5 AC |
55 | /* Do the actual work of inserting a breakpoint into the instruction |
56 | stream. */ | |
b9d580a4 SG |
57 | |
58 | static void | |
59 | insert_breakpoint (sd, bp) | |
60 | SIM_DESC sd; | |
61 | struct sim_breakpoint *bp; | |
62 | { | |
63 | if (bp->flags & (SIM_BREAK_INSERTED | SIM_BREAK_DISABLED)) | |
64 | return; | |
65 | ||
eefc25e5 | 66 | sim_core_read_buffer (sd, NULL, exec_map, bp->loc_contents, |
b9d580a4 | 67 | bp->addr, SIM_BREAKPOINT_SIZE); |
eefc25e5 | 68 | sim_core_write_buffer (sd, NULL, exec_map, sim_breakpoint, |
b9d580a4 SG |
69 | bp->addr, SIM_BREAKPOINT_SIZE); |
70 | bp->flags |= SIM_BREAK_INSERTED; | |
71 | } | |
72 | ||
73 | /* Do the actual work of removing a breakpoint. */ | |
74 | ||
75 | static void | |
76 | remove_breakpoint (sd, bp) | |
77 | SIM_DESC sd; | |
78 | struct sim_breakpoint *bp; | |
79 | { | |
80 | if (!(bp->flags & SIM_BREAK_INSERTED)) | |
81 | return; | |
82 | ||
eefc25e5 | 83 | sim_core_write_buffer (sd, NULL, exec_map, bp->loc_contents, |
b9d580a4 | 84 | bp->addr, SIM_BREAKPOINT_SIZE); |
84c6d152 | 85 | bp->flags &= ~SIM_BREAK_INSERTED; |
b9d580a4 SG |
86 | } |
87 | ||
88 | /* Come here when a breakpoint insn is hit. If it's really a breakpoint, we | |
89 | halt things, and never return. If it's a false hit, we return to let the | |
90 | caller handle things. */ | |
91 | ||
92 | void | |
93 | sim_handle_breakpoint (sd, cpu, cia) | |
94 | SIM_DESC sd; | |
95 | sim_cpu *cpu; | |
96 | sim_cia cia; | |
97 | { | |
98 | struct sim_breakpoint *bp; | |
99 | ||
100 | for (bp = STATE_BREAKPOINTS (sd); bp; bp = bp->next) | |
13c9499d | 101 | if (bp->addr == CIA_ADDR (cia)) |
b9d580a4 SG |
102 | break; |
103 | ||
104 | if (!bp || !(bp->flags & SIM_BREAK_INSERTED)) | |
105 | return; | |
106 | ||
1ebc7e0e | 107 | sim_engine_halt (sd, STATE_CPU (sd, 0), NULL, cia, sim_stopped, SIM_SIGTRAP); |
b9d580a4 SG |
108 | } |
109 | ||
110 | /* Handler functions for simulator resume and suspend events. */ | |
111 | ||
112 | static SIM_RC | |
113 | resume_handler (sd) | |
114 | SIM_DESC sd; | |
115 | { | |
116 | struct sim_breakpoint *bp; | |
117 | ||
118 | for (bp = STATE_BREAKPOINTS (sd); bp; bp = bp->next) | |
119 | insert_breakpoint (sd, bp); | |
120 | ||
121 | return SIM_RC_OK; | |
122 | } | |
123 | ||
124 | static SIM_RC | |
125 | suspend_handler (sd) | |
126 | SIM_DESC sd; | |
127 | { | |
128 | struct sim_breakpoint *bp; | |
129 | ||
130 | for (bp = STATE_BREAKPOINTS (sd); bp; bp = bp->next) | |
131 | remove_breakpoint (sd, bp); | |
132 | ||
133 | return SIM_RC_OK; | |
134 | } | |
135 | ||
136 | /* Called from simulator module initialization. */ | |
137 | ||
138 | SIM_RC | |
139 | sim_break_install (sd) | |
140 | SIM_DESC sd; | |
141 | { | |
142 | sim_module_add_resume_fn (sd, resume_handler); | |
143 | sim_module_add_suspend_fn (sd, suspend_handler); | |
144 | ||
145 | return SIM_RC_OK; | |
146 | } | |
147 | ||
148 | /* Install a breakpoint. This is a user-function. The breakpoint isn't | |
149 | actually installed here. We just record it. Resume_handler does the | |
150 | actual work. | |
151 | */ | |
152 | ||
153 | SIM_RC | |
154 | sim_set_breakpoint (sd, addr) | |
155 | SIM_DESC sd; | |
156 | SIM_ADDR addr; | |
157 | { | |
158 | struct sim_breakpoint *bp; | |
159 | ||
160 | for (bp = STATE_BREAKPOINTS (sd); bp; bp = bp->next) | |
161 | if (bp->addr == addr) | |
162 | return SIM_RC_DUPLICATE_BREAKPOINT; /* Already there */ | |
163 | else | |
84c6d152 | 164 | break; /* FIXME: why not scan all bp's? */ |
b9d580a4 | 165 | |
68f92f98 | 166 | bp = ZALLOC (struct sim_breakpoint); |
b9d580a4 SG |
167 | |
168 | bp->addr = addr; | |
169 | bp->next = STATE_BREAKPOINTS (sd); | |
170 | bp->flags = 0; | |
171 | STATE_BREAKPOINTS (sd) = bp; | |
172 | ||
173 | return SIM_RC_OK; | |
174 | } | |
175 | ||
176 | /* Delete a breakpoint. All knowlege of the breakpoint is removed from the | |
177 | simulator. | |
178 | */ | |
179 | ||
180 | SIM_RC | |
181 | sim_clear_breakpoint (sd, addr) | |
182 | SIM_DESC sd; | |
183 | SIM_ADDR addr; | |
184 | { | |
185 | struct sim_breakpoint *bp, *bpprev; | |
186 | ||
187 | for (bp = STATE_BREAKPOINTS (sd), bpprev = NULL; | |
188 | bp; | |
189 | bpprev = bp, bp = bp->next) | |
190 | if (bp->addr == addr) | |
191 | break; | |
192 | ||
193 | if (!bp) | |
194 | return SIM_RC_UNKNOWN_BREAKPOINT; | |
195 | ||
196 | remove_breakpoint (sd, bp); | |
197 | ||
198 | if (bpprev) | |
199 | bpprev->next = bp->next; | |
200 | else | |
201 | STATE_BREAKPOINTS (sd) = NULL; | |
202 | ||
68f92f98 | 203 | zfree (bp); |
b9d580a4 SG |
204 | |
205 | return SIM_RC_OK; | |
206 | } | |
207 | ||
208 | SIM_RC | |
209 | sim_clear_all_breakpoints (sd) | |
210 | SIM_DESC sd; | |
211 | { | |
212 | while (STATE_BREAKPOINTS (sd)) | |
213 | sim_clear_breakpoint (sd, STATE_BREAKPOINTS (sd)->addr); | |
214 | ||
215 | return SIM_RC_OK; | |
216 | } | |
217 | ||
218 | SIM_RC | |
219 | sim_enable_breakpoint (sd, addr) | |
220 | SIM_DESC sd; | |
221 | SIM_ADDR addr; | |
222 | { | |
223 | struct sim_breakpoint *bp; | |
224 | ||
225 | for (bp = STATE_BREAKPOINTS (sd); bp; bp = bp->next) | |
226 | if (bp->addr == addr) | |
227 | break; | |
228 | ||
229 | if (!bp) | |
230 | return SIM_RC_UNKNOWN_BREAKPOINT; | |
231 | ||
232 | bp->flags &= ~SIM_BREAK_DISABLED; | |
233 | ||
234 | return SIM_RC_OK; | |
235 | } | |
236 | ||
237 | SIM_RC | |
238 | sim_disable_breakpoint (sd, addr) | |
239 | SIM_DESC sd; | |
240 | SIM_ADDR addr; | |
241 | { | |
242 | struct sim_breakpoint *bp; | |
243 | ||
244 | for (bp = STATE_BREAKPOINTS (sd); bp; bp = bp->next) | |
245 | if (bp->addr == addr) | |
246 | break; | |
247 | ||
248 | if (!bp) | |
249 | return SIM_RC_UNKNOWN_BREAKPOINT; | |
250 | ||
251 | bp->flags |= SIM_BREAK_DISABLED; | |
252 | ||
253 | return SIM_RC_OK; | |
254 | } | |
255 | ||
256 | SIM_RC | |
257 | sim_enable_all_breakpoints (sd) | |
258 | SIM_DESC sd; | |
259 | { | |
260 | struct sim_breakpoint *bp; | |
261 | ||
262 | for (bp = STATE_BREAKPOINTS (sd); bp; bp = bp->next) | |
263 | bp->flags &= ~SIM_BREAK_DISABLED; | |
264 | ||
265 | return SIM_RC_OK; | |
266 | } | |
267 | ||
268 | SIM_RC | |
269 | sim_disable_all_breakpoints (sd) | |
270 | SIM_DESC sd; | |
271 | { | |
272 | struct sim_breakpoint *bp; | |
273 | ||
274 | for (bp = STATE_BREAKPOINTS (sd); bp; bp = bp->next) | |
275 | bp->flags |= SIM_BREAK_DISABLED; | |
276 | ||
277 | return SIM_RC_OK; | |
278 | } |