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