OSDN Git Service

Switch the license of all .c files to GPLv3.
[pf3gnuchains/pf3gnuchains3x.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 }