9d89326b06cbc9ae55d155ad13aa924e3905b99e
[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 void
50 set_breakpoint_at (CORE_ADDR where, int (*handler) (CORE_ADDR))
51 {
52 struct process_info *proc = current_process ();
53 struct breakpoint *bp;
54
55 if (breakpoint_data == NULL)
56 error ("Target does not support breakpoints.");
57
58 bp = xmalloc (sizeof (struct breakpoint));
59 memset (bp, 0, sizeof (struct breakpoint));
60
61 (*the_target->read_memory) (where, bp->old_data,
62 breakpoint_len);
63 (*the_target->write_memory) (where, breakpoint_data,
64 breakpoint_len);
65
66 bp->pc = where;
67 bp->handler = handler;
68
69 bp->next = proc->breakpoints;
70 proc->breakpoints = bp;
71 }
72
73 static void
74 delete_breakpoint (struct breakpoint *bp)
75 {
76 struct process_info *proc = current_process ();
77 struct breakpoint *cur;
78
79 if (proc->breakpoints == bp)
80 {
81 proc->breakpoints = bp->next;
82 (*the_target->write_memory) (bp->pc, bp->old_data,
83 breakpoint_len);
84 free (bp);
85 return;
86 }
87 cur = proc->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 process_info *proc = current_process ();
106 struct breakpoint *bp = proc->breakpoints;
107
108 while (bp != NULL)
109 {
110 if (bp->pc == where)
111 return bp;
112 bp = bp->next;
113 }
114
115 return NULL;
116 }
117
118 void
119 delete_breakpoint_at (CORE_ADDR addr)
120 {
121 struct breakpoint *bp = find_breakpoint_at (addr);
122 if (bp != NULL)
123 delete_breakpoint (bp);
124 }
125
126 static int
127 reinsert_breakpoint_handler (CORE_ADDR stop_pc)
128 {
129 struct breakpoint *stop_bp, *orig_bp;
130
131 stop_bp = find_breakpoint_at (stop_pc);
132 if (stop_bp == NULL)
133 error ("lost the stopping breakpoint.");
134
135 orig_bp = stop_bp->breakpoint_to_reinsert;
136 if (orig_bp == NULL)
137 error ("no breakpoint to reinsert");
138
139 (*the_target->write_memory) (orig_bp->pc, breakpoint_data,
140 breakpoint_len);
141 orig_bp->reinserting = 0;
142 return 1;
143 }
144
145 void
146 reinsert_breakpoint_by_bp (CORE_ADDR stop_pc, CORE_ADDR stop_at)
147 {
148 struct breakpoint *bp, *orig_bp;
149
150 orig_bp = find_breakpoint_at (stop_pc);
151 if (orig_bp == NULL)
152 error ("Could not find original breakpoint in list.");
153
154 set_breakpoint_at (stop_at, reinsert_breakpoint_handler);
155
156 bp = find_breakpoint_at (stop_at);
157 if (bp == NULL)
158 error ("Could not find breakpoint in list (reinserting by breakpoint).");
159 bp->breakpoint_to_reinsert = orig_bp;
160
161 (*the_target->write_memory) (orig_bp->pc, orig_bp->old_data,
162 breakpoint_len);
163 orig_bp->reinserting = 1;
164 }
165
166 void
167 uninsert_breakpoint (CORE_ADDR stopped_at)
168 {
169 struct breakpoint *bp;
170
171 bp = find_breakpoint_at (stopped_at);
172 if (bp == NULL)
173 error ("Could not find breakpoint in list (uninserting).");
174
175 (*the_target->write_memory) (bp->pc, bp->old_data,
176 breakpoint_len);
177 bp->reinserting = 1;
178 }
179
180 void
181 reinsert_breakpoint (CORE_ADDR stopped_at)
182 {
183 struct breakpoint *bp;
184
185 bp = find_breakpoint_at (stopped_at);
186 if (bp == NULL)
187 error ("Could not find breakpoint in list (uninserting).");
188 if (! bp->reinserting)
189 error ("Breakpoint already inserted at reinsert time.");
190
191 (*the_target->write_memory) (bp->pc, breakpoint_data,
192 breakpoint_len);
193 bp->reinserting = 0;
194 }
195
196 int
197 check_breakpoints (CORE_ADDR stop_pc)
198 {
199 struct breakpoint *bp;
200
201 bp = find_breakpoint_at (stop_pc);
202 if (bp == NULL)
203 return 0;
204 if (bp->reinserting)
205 {
206 warning ("Hit a removed breakpoint?");
207 return 0;
208 }
209
210 if ((*bp->handler) (bp->pc))
211 {
212 delete_breakpoint (bp);
213 return 2;
214 }
215 else
216 return 1;
217 }
218
219 void
220 set_breakpoint_data (const unsigned char *bp_data, int bp_len)
221 {
222 breakpoint_data = bp_data;
223 breakpoint_len = bp_len;
224 }
225
226 void
227 check_mem_read (CORE_ADDR mem_addr, unsigned char *buf, int mem_len)
228 {
229 struct process_info *proc = current_process ();
230 struct breakpoint *bp = proc->breakpoints;
231 CORE_ADDR mem_end = mem_addr + mem_len;
232
233 for (; bp != NULL; bp = bp->next)
234 {
235 CORE_ADDR bp_end = bp->pc + breakpoint_len;
236 CORE_ADDR start, end;
237 int copy_offset, copy_len, buf_offset;
238
239 if (mem_addr >= bp_end)
240 continue;
241 if (bp->pc >= mem_end)
242 continue;
243
244 start = bp->pc;
245 if (mem_addr > start)
246 start = mem_addr;
247
248 end = bp_end;
249 if (end > mem_end)
250 end = mem_end;
251
252 copy_len = end - start;
253 copy_offset = start - bp->pc;
254 buf_offset = start - mem_addr;
255
256 memcpy (buf + buf_offset, bp->old_data + copy_offset, copy_len);
257 }
258 }
259
260 void
261 check_mem_write (CORE_ADDR mem_addr, unsigned char *buf, int mem_len)
262 {
263 struct process_info *proc = current_process ();
264 struct breakpoint *bp = proc->breakpoints;
265 CORE_ADDR mem_end = mem_addr + mem_len;
266
267 for (; bp != NULL; bp = bp->next)
268 {
269 CORE_ADDR bp_end = bp->pc + breakpoint_len;
270 CORE_ADDR start, end;
271 int copy_offset, copy_len, buf_offset;
272
273 if (mem_addr >= bp_end)
274 continue;
275 if (bp->pc >= mem_end)
276 continue;
277
278 start = bp->pc;
279 if (mem_addr > start)
280 start = mem_addr;
281
282 end = bp_end;
283 if (end > mem_end)
284 end = mem_end;
285
286 copy_len = end - start;
287 copy_offset = start - bp->pc;
288 buf_offset = start - mem_addr;
289
290 memcpy (bp->old_data + copy_offset, buf + buf_offset, copy_len);
291 if (bp->reinserting == 0)
292 memcpy (buf + buf_offset, breakpoint_data + copy_offset, copy_len);
293 }
294 }
295
296 /* Delete all breakpoints, and un-insert them from the inferior. */
297
298 void
299 delete_all_breakpoints (void)
300 {
301 struct process_info *proc = current_process ();
302
303 while (proc->breakpoints)
304 delete_breakpoint (proc->breakpoints);
305 }
306
307 /* Release all breakpoints, but do not try to un-insert them from the
308 inferior. */
309
310 void
311 free_all_breakpoints (struct process_info *proc)
312 {
313 struct breakpoint *bp;
314
315 while (proc->breakpoints)
316 {
317 bp = proc->breakpoints;
318 proc->breakpoints = bp->next;
319 free (bp);
320 }
321 }
This page took 0.037313 seconds and 4 git commands to generate.