]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - gdb/gdbserver/mem-break.c
* linux-arm-low.c:
[thirdparty/binutils-gdb.git] / gdb / gdbserver / mem-break.c
CommitLineData
611cb4a5 1/* Memory breakpoint operations for the remote server for GDB.
6f0f660e 2 Copyright (C) 2002, 2003, 2005
611cb4a5
DJ
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 2 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, write to the Free Software
6f0f660e
EZ
21 Foundation, Inc., 51 Franklin Street, Fifth Floor,
22 Boston, MA 02110-1301, USA. */
611cb4a5
DJ
23
24#include "server.h"
25
f450004a 26const unsigned char *breakpoint_data;
611cb4a5
DJ
27int breakpoint_len;
28
29#define MAX_BREAKPOINT_LEN 8
30
31struct breakpoint
32{
33 struct breakpoint *next;
34 CORE_ADDR pc;
35 unsigned char old_data[MAX_BREAKPOINT_LEN];
36
37 /* Non-zero iff we are stepping over this breakpoint. */
38 int reinserting;
39
40 /* Non-NULL iff this breakpoint was inserted to step over
41 another one. Points to the other breakpoint (which is also
42 in the *next chain somewhere). */
43 struct breakpoint *breakpoint_to_reinsert;
44
45 /* Function to call when we hit this breakpoint. */
46 void (*handler) (CORE_ADDR);
47};
48
49struct breakpoint *breakpoints;
50
51void
52set_breakpoint_at (CORE_ADDR where, void (*handler) (CORE_ADDR))
53{
54 struct breakpoint *bp;
55
56 if (breakpoint_data == NULL)
57 error ("Target does not support breakpoints.");
58
59 bp = malloc (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
74static void
75delete_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
102static struct breakpoint *
103find_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
117static void
118reinsert_breakpoint_handler (CORE_ADDR stop_pc)
119{
120 struct breakpoint *stop_bp, *orig_bp;
121
122 stop_bp = find_breakpoint_at (stop_pc);
123 if (stop_bp == NULL)
124 error ("lost the stopping breakpoint.");
125
126 orig_bp = stop_bp->breakpoint_to_reinsert;
127 if (orig_bp == NULL)
128 error ("no breakpoint to reinsert");
129
130 (*the_target->write_memory) (orig_bp->pc, breakpoint_data,
131 breakpoint_len);
132 orig_bp->reinserting = 0;
133 delete_breakpoint (stop_bp);
134}
135
136void
137reinsert_breakpoint_by_bp (CORE_ADDR stop_pc, CORE_ADDR stop_at)
138{
139 struct breakpoint *bp, *orig_bp;
140
141 set_breakpoint_at (stop_at, reinsert_breakpoint_handler);
142
fd3a5ca1 143 orig_bp = find_breakpoint_at (stop_pc);
611cb4a5
DJ
144 if (orig_bp == NULL)
145 error ("Could not find original breakpoint in list.");
146
147 bp = find_breakpoint_at (stop_at);
148 if (bp == NULL)
149 error ("Could not find breakpoint in list (reinserting by breakpoint).");
150 bp->breakpoint_to_reinsert = orig_bp;
151
152 (*the_target->write_memory) (orig_bp->pc, orig_bp->old_data,
153 breakpoint_len);
154 orig_bp->reinserting = 1;
155}
156
157void
158uninsert_breakpoint (CORE_ADDR stopped_at)
159{
160 struct breakpoint *bp;
161
162 bp = find_breakpoint_at (stopped_at);
163 if (bp == NULL)
164 error ("Could not find breakpoint in list (uninserting).");
165
166 (*the_target->write_memory) (bp->pc, bp->old_data,
167 breakpoint_len);
168 bp->reinserting = 1;
169}
170
171void
172reinsert_breakpoint (CORE_ADDR stopped_at)
173{
174 struct breakpoint *bp;
175
176 bp = find_breakpoint_at (stopped_at);
177 if (bp == NULL)
178 error ("Could not find breakpoint in list (uninserting).");
179 if (! bp->reinserting)
180 error ("Breakpoint already inserted at reinsert time.");
181
182 (*the_target->write_memory) (bp->pc, breakpoint_data,
183 breakpoint_len);
184 bp->reinserting = 0;
185}
186
187int
188check_breakpoints (CORE_ADDR stop_pc)
189{
190 struct breakpoint *bp;
191
192 bp = find_breakpoint_at (stop_pc);
193 if (bp == NULL)
194 return 0;
195 if (bp->reinserting)
196 {
197 warning ("Hit a removed breakpoint?");
198 return 0;
199 }
200
201 (*bp->handler) (bp->pc);
202 return 1;
203}
204
205void
f450004a 206set_breakpoint_data (const unsigned char *bp_data, int bp_len)
611cb4a5
DJ
207{
208 breakpoint_data = bp_data;
209 breakpoint_len = bp_len;
210}
211
212void
f450004a 213check_mem_read (CORE_ADDR mem_addr, unsigned char *buf, int mem_len)
611cb4a5
DJ
214{
215 struct breakpoint *bp = breakpoints;
216 CORE_ADDR mem_end = mem_addr + mem_len;
217
218 for (; bp != NULL; bp = bp->next)
219 {
220 CORE_ADDR bp_end = bp->pc + breakpoint_len;
221 CORE_ADDR start, end;
222 int copy_offset, copy_len, buf_offset;
223
224 if (mem_addr >= bp_end)
225 continue;
226 if (bp->pc >= mem_end)
227 continue;
228
229 start = bp->pc;
230 if (mem_addr > start)
231 start = mem_addr;
232
233 end = bp_end;
234 if (end > mem_end)
235 end = mem_end;
236
237 copy_len = end - start;
238 copy_offset = start - bp->pc;
239 buf_offset = start - mem_addr;
240
241 memcpy (buf + buf_offset, bp->old_data + copy_offset, copy_len);
242 }
243}
244
245void
f450004a 246check_mem_write (CORE_ADDR mem_addr, unsigned char *buf, int mem_len)
611cb4a5
DJ
247{
248 struct breakpoint *bp = breakpoints;
249 CORE_ADDR mem_end = mem_addr + mem_len;
250
251 for (; bp != NULL; bp = bp->next)
252 {
253 CORE_ADDR bp_end = bp->pc + breakpoint_len;
254 CORE_ADDR start, end;
255 int copy_offset, copy_len, buf_offset;
256
257 if (mem_addr >= bp_end)
258 continue;
259 if (bp->pc >= mem_end)
260 continue;
261
262 start = bp->pc;
263 if (mem_addr > start)
264 start = mem_addr;
265
266 end = bp_end;
267 if (end > mem_end)
268 end = mem_end;
269
270 copy_len = end - start;
271 copy_offset = start - bp->pc;
272 buf_offset = start - mem_addr;
273
274 memcpy (bp->old_data + copy_offset, buf + buf_offset, copy_len);
275 if (bp->reinserting == 0)
276 memcpy (buf + buf_offset, breakpoint_data + copy_offset, copy_len);
277 }
278}