2009-01-30 Julian Brown <julian@codesourcery.com>
[deliverable/binutils-gdb.git] / gdb / gdbserver / mem-break.c
1 /* Memory breakpoint operations for the remote server for GDB.
2 Copyright (C) 2002, 2003, 2005, 2007, 2008, 2009
3 Free Software Foundation, Inc.
4
5 Contributed by MontaVista Software.
6
7 This file is part of GDB.
8
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>. */
21
22 #include "server.h"
23
24 const unsigned char *breakpoint_data;
25 int breakpoint_len;
26
27 #define MAX_BREAKPOINT_LEN 8
28
29 struct breakpoint
30 {
31 struct breakpoint *next;
32 CORE_ADDR pc;
33 unsigned char old_data[MAX_BREAKPOINT_LEN];
34
35 /* Non-zero iff we are stepping over this breakpoint. */
36 int reinserting;
37
38 /* Non-NULL iff this breakpoint was inserted to step over
39 another one. Points to the other breakpoint (which is also
40 in the *next chain somewhere). */
41 struct breakpoint *breakpoint_to_reinsert;
42
43 /* Function to call when we hit this breakpoint. If it returns 1,
44 the breakpoint will be deleted; 0, it will be reinserted for
45 another round. */
46 int (*handler) (CORE_ADDR);
47 };
48
49 struct breakpoint *breakpoints;
50
51 void
52 set_breakpoint_at (CORE_ADDR where, int (*handler) (CORE_ADDR))
53 {
54 struct breakpoint *bp;
55
56 if (breakpoint_data == NULL)
57 error ("Target does not support breakpoints.");
58
59 bp = xmalloc (sizeof (struct breakpoint));
60 memset (bp, 0, sizeof (struct breakpoint));
61
62 (*the_target->read_memory) (where, bp->old_data,
63 breakpoint_len);
64 (*the_target->write_memory) (where, breakpoint_data,
65 breakpoint_len);
66
67 bp->pc = where;
68 bp->handler = handler;
69
70 bp->next = breakpoints;
71 breakpoints = bp;
72 }
73
74 static void
75 delete_breakpoint (struct breakpoint *bp)
76 {
77 struct breakpoint *cur;
78
79 if (breakpoints == bp)
80 {
81 breakpoints = bp->next;
82 (*the_target->write_memory) (bp->pc, bp->old_data,
83 breakpoint_len);
84 free (bp);
85 return;
86 }
87 cur = breakpoints;
88 while (cur->next)
89 {
90 if (cur->next == bp)
91 {
92 cur->next = bp->next;
93 (*the_target->write_memory) (bp->pc, bp->old_data,
94 breakpoint_len);
95 free (bp);
96 return;
97 }
98 }
99 warning ("Could not find breakpoint in list.");
100 }
101
102 static struct breakpoint *
103 find_breakpoint_at (CORE_ADDR where)
104 {
105 struct breakpoint *bp = breakpoints;
106
107 while (bp != NULL)
108 {
109 if (bp->pc == where)
110 return bp;
111 bp = bp->next;
112 }
113
114 return NULL;
115 }
116
117 void
118 delete_breakpoint_at (CORE_ADDR addr)
119 {
120 struct breakpoint *bp = find_breakpoint_at (addr);
121 if (bp != NULL)
122 delete_breakpoint (bp);
123 }
124
125 static int
126 reinsert_breakpoint_handler (CORE_ADDR stop_pc)
127 {
128 struct breakpoint *stop_bp, *orig_bp;
129
130 stop_bp = find_breakpoint_at (stop_pc);
131 if (stop_bp == NULL)
132 error ("lost the stopping breakpoint.");
133
134 orig_bp = stop_bp->breakpoint_to_reinsert;
135 if (orig_bp == NULL)
136 error ("no breakpoint to reinsert");
137
138 (*the_target->write_memory) (orig_bp->pc, breakpoint_data,
139 breakpoint_len);
140 orig_bp->reinserting = 0;
141 return 1;
142 }
143
144 void
145 reinsert_breakpoint_by_bp (CORE_ADDR stop_pc, CORE_ADDR stop_at)
146 {
147 struct breakpoint *bp, *orig_bp;
148
149 orig_bp = find_breakpoint_at (stop_pc);
150 if (orig_bp == NULL)
151 error ("Could not find original breakpoint in list.");
152
153 set_breakpoint_at (stop_at, reinsert_breakpoint_handler);
154
155 bp = find_breakpoint_at (stop_at);
156 if (bp == NULL)
157 error ("Could not find breakpoint in list (reinserting by breakpoint).");
158 bp->breakpoint_to_reinsert = orig_bp;
159
160 (*the_target->write_memory) (orig_bp->pc, orig_bp->old_data,
161 breakpoint_len);
162 orig_bp->reinserting = 1;
163 }
164
165 void
166 uninsert_breakpoint (CORE_ADDR stopped_at)
167 {
168 struct breakpoint *bp;
169
170 bp = find_breakpoint_at (stopped_at);
171 if (bp == NULL)
172 error ("Could not find breakpoint in list (uninserting).");
173
174 (*the_target->write_memory) (bp->pc, bp->old_data,
175 breakpoint_len);
176 bp->reinserting = 1;
177 }
178
179 void
180 reinsert_breakpoint (CORE_ADDR stopped_at)
181 {
182 struct breakpoint *bp;
183
184 bp = find_breakpoint_at (stopped_at);
185 if (bp == NULL)
186 error ("Could not find breakpoint in list (uninserting).");
187 if (! bp->reinserting)
188 error ("Breakpoint already inserted at reinsert time.");
189
190 (*the_target->write_memory) (bp->pc, breakpoint_data,
191 breakpoint_len);
192 bp->reinserting = 0;
193 }
194
195 int
196 check_breakpoints (CORE_ADDR stop_pc)
197 {
198 struct breakpoint *bp;
199
200 bp = find_breakpoint_at (stop_pc);
201 if (bp == NULL)
202 return 0;
203 if (bp->reinserting)
204 {
205 warning ("Hit a removed breakpoint?");
206 return 0;
207 }
208
209 if ((*bp->handler) (bp->pc))
210 {
211 delete_breakpoint (bp);
212 return 2;
213 }
214 else
215 return 1;
216 }
217
218 void
219 set_breakpoint_data (const unsigned char *bp_data, int bp_len)
220 {
221 breakpoint_data = bp_data;
222 breakpoint_len = bp_len;
223 }
224
225 void
226 check_mem_read (CORE_ADDR mem_addr, unsigned char *buf, int mem_len)
227 {
228 struct breakpoint *bp = breakpoints;
229 CORE_ADDR mem_end = mem_addr + mem_len;
230
231 for (; bp != NULL; bp = bp->next)
232 {
233 CORE_ADDR bp_end = bp->pc + breakpoint_len;
234 CORE_ADDR start, end;
235 int copy_offset, copy_len, buf_offset;
236
237 if (mem_addr >= bp_end)
238 continue;
239 if (bp->pc >= mem_end)
240 continue;
241
242 start = bp->pc;
243 if (mem_addr > start)
244 start = mem_addr;
245
246 end = bp_end;
247 if (end > mem_end)
248 end = mem_end;
249
250 copy_len = end - start;
251 copy_offset = start - bp->pc;
252 buf_offset = start - mem_addr;
253
254 memcpy (buf + buf_offset, bp->old_data + copy_offset, copy_len);
255 }
256 }
257
258 void
259 check_mem_write (CORE_ADDR mem_addr, unsigned char *buf, int mem_len)
260 {
261 struct breakpoint *bp = breakpoints;
262 CORE_ADDR mem_end = mem_addr + mem_len;
263
264 for (; bp != NULL; bp = bp->next)
265 {
266 CORE_ADDR bp_end = bp->pc + breakpoint_len;
267 CORE_ADDR start, end;
268 int copy_offset, copy_len, buf_offset;
269
270 if (mem_addr >= bp_end)
271 continue;
272 if (bp->pc >= mem_end)
273 continue;
274
275 start = bp->pc;
276 if (mem_addr > start)
277 start = mem_addr;
278
279 end = bp_end;
280 if (end > mem_end)
281 end = mem_end;
282
283 copy_len = end - start;
284 copy_offset = start - bp->pc;
285 buf_offset = start - mem_addr;
286
287 memcpy (bp->old_data + copy_offset, buf + buf_offset, copy_len);
288 if (bp->reinserting == 0)
289 memcpy (buf + buf_offset, breakpoint_data + copy_offset, copy_len);
290 }
291 }
292
293 /* Delete all breakpoints. */
294
295 void
296 delete_all_breakpoints (void)
297 {
298 while (breakpoints)
299 delete_breakpoint (breakpoints);
300 }
This page took 0.046124 seconds and 4 git commands to generate.