OSDN Git Service

Updated copyright notices for most files.
[pf3gnuchains/pf3gnuchains4x.git] / gdb / gdbserver / mem-break.c
1 /* Memory breakpoint operations for the remote server for GDB.
2    Copyright (C) 2002, 2003, 2005, 2007, 2008 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.  If it returns 1,
43      the breakpoint will be deleted; 0, it will be reinserted for
44      another round.  */
45   int (*handler) (CORE_ADDR);
46 };
47
48 struct breakpoint *breakpoints;
49
50 void
51 set_breakpoint_at (CORE_ADDR where, int (*handler) (CORE_ADDR))
52 {
53   struct breakpoint *bp;
54
55   if (breakpoint_data == NULL)
56     error ("Target does not support breakpoints.");
57
58   bp = malloc (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 = breakpoints;
70   breakpoints = bp;
71 }
72
73 static void
74 delete_breakpoint (struct breakpoint *bp)
75 {
76   struct breakpoint *cur;
77
78   if (breakpoints == bp)
79     {
80       breakpoints = bp->next;
81       (*the_target->write_memory) (bp->pc, bp->old_data,
82                                    breakpoint_len);
83       free (bp);
84       return;
85     }
86   cur = breakpoints;
87   while (cur->next)
88     {
89       if (cur->next == bp)
90         {
91           cur->next = bp->next;
92           (*the_target->write_memory) (bp->pc, bp->old_data,
93                                        breakpoint_len);
94           free (bp);
95           return;
96         }
97     }
98   warning ("Could not find breakpoint in list.");
99 }
100
101 static struct breakpoint *
102 find_breakpoint_at (CORE_ADDR where)
103 {
104   struct breakpoint *bp = breakpoints;
105
106   while (bp != NULL)
107     {
108       if (bp->pc == where)
109         return bp;
110       bp = bp->next;
111     }
112
113   return NULL;
114 }
115
116 void
117 delete_breakpoint_at (CORE_ADDR addr)
118 {
119   struct breakpoint *bp = find_breakpoint_at (addr);
120   if (bp != NULL)
121     delete_breakpoint (bp);
122 }
123
124 static int
125 reinsert_breakpoint_handler (CORE_ADDR stop_pc)
126 {
127   struct breakpoint *stop_bp, *orig_bp;
128
129   stop_bp = find_breakpoint_at (stop_pc);
130   if (stop_bp == NULL)
131     error ("lost the stopping breakpoint.");
132
133   orig_bp = stop_bp->breakpoint_to_reinsert;
134   if (orig_bp == NULL)
135     error ("no breakpoint to reinsert");
136
137   (*the_target->write_memory) (orig_bp->pc, breakpoint_data,
138                                breakpoint_len);
139   orig_bp->reinserting = 0;
140   return 1;
141 }
142
143 void
144 reinsert_breakpoint_by_bp (CORE_ADDR stop_pc, CORE_ADDR stop_at)
145 {
146   struct breakpoint *bp, *orig_bp;
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   set_breakpoint_at (stop_at, reinsert_breakpoint_handler);
153
154   bp = find_breakpoint_at (stop_at);
155   if (bp == NULL)
156     error ("Could not find breakpoint in list (reinserting by breakpoint).");
157   bp->breakpoint_to_reinsert = orig_bp;
158
159   (*the_target->write_memory) (orig_bp->pc, orig_bp->old_data,
160                                breakpoint_len);
161   orig_bp->reinserting = 1;
162 }
163
164 void
165 uninsert_breakpoint (CORE_ADDR stopped_at)
166 {
167   struct breakpoint *bp;
168
169   bp = find_breakpoint_at (stopped_at);
170   if (bp == NULL)
171     error ("Could not find breakpoint in list (uninserting).");
172
173   (*the_target->write_memory) (bp->pc, bp->old_data,
174                                breakpoint_len);
175   bp->reinserting = 1;
176 }
177
178 void
179 reinsert_breakpoint (CORE_ADDR stopped_at)
180 {
181   struct breakpoint *bp;
182
183   bp = find_breakpoint_at (stopped_at);
184   if (bp == NULL)
185     error ("Could not find breakpoint in list (uninserting).");
186   if (! bp->reinserting)
187     error ("Breakpoint already inserted at reinsert time.");
188
189   (*the_target->write_memory) (bp->pc, breakpoint_data,
190                                breakpoint_len);
191   bp->reinserting = 0;
192 }
193
194 int
195 check_breakpoints (CORE_ADDR stop_pc)
196 {
197   struct breakpoint *bp;
198
199   bp = find_breakpoint_at (stop_pc);
200   if (bp == NULL)
201     return 0;
202   if (bp->reinserting)
203     {
204       warning ("Hit a removed breakpoint?");
205       return 0;
206     }
207
208   if ((*bp->handler) (bp->pc))
209     {
210       delete_breakpoint (bp);
211       return 2;
212     }
213   else
214     return 1;
215 }
216
217 void
218 set_breakpoint_data (const unsigned char *bp_data, int bp_len)
219 {
220   breakpoint_data = bp_data;
221   breakpoint_len = bp_len;
222 }
223
224 void
225 check_mem_read (CORE_ADDR mem_addr, unsigned char *buf, int mem_len)
226 {
227   struct breakpoint *bp = breakpoints;
228   CORE_ADDR mem_end = mem_addr + mem_len;
229
230   for (; bp != NULL; bp = bp->next)
231     {
232       CORE_ADDR bp_end = bp->pc + breakpoint_len;
233       CORE_ADDR start, end;
234       int copy_offset, copy_len, buf_offset;
235
236       if (mem_addr >= bp_end)
237         continue;
238       if (bp->pc >= mem_end)
239         continue;
240
241       start = bp->pc;
242       if (mem_addr > start)
243         start = mem_addr;
244
245       end = bp_end;
246       if (end > mem_end)
247         end = mem_end;
248
249       copy_len = end - start;
250       copy_offset = start - bp->pc;
251       buf_offset = start - mem_addr;
252
253       memcpy (buf + buf_offset, bp->old_data + copy_offset, copy_len);
254     }
255 }
256
257 void
258 check_mem_write (CORE_ADDR mem_addr, unsigned char *buf, int mem_len)
259 {
260   struct breakpoint *bp = breakpoints;
261   CORE_ADDR mem_end = mem_addr + mem_len;
262
263   for (; bp != NULL; bp = bp->next)
264     {
265       CORE_ADDR bp_end = bp->pc + breakpoint_len;
266       CORE_ADDR start, end;
267       int copy_offset, copy_len, buf_offset;
268
269       if (mem_addr >= bp_end)
270         continue;
271       if (bp->pc >= mem_end)
272         continue;
273
274       start = bp->pc;
275       if (mem_addr > start)
276         start = mem_addr;
277
278       end = bp_end;
279       if (end > mem_end)
280         end = mem_end;
281
282       copy_len = end - start;
283       copy_offset = start - bp->pc;
284       buf_offset = start - mem_addr;
285
286       memcpy (bp->old_data + copy_offset, buf + buf_offset, copy_len);
287       if (bp->reinserting == 0)
288         memcpy (buf + buf_offset, breakpoint_data + copy_offset, copy_len);
289     }
290 }
291
292 /* Delete all breakpoints.  */
293
294 void
295 delete_all_breakpoints (void)
296 {
297   while (breakpoints)
298     delete_breakpoint (breakpoints);
299 }