Revert "Revert "and added files""
[bcm963xx.git] / userapps / opensource / gdbserver / mem-break.c
1 /* Memory breakpoint operations for the remote server for GDB.
2    Copyright 2002
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
21    Foundation, Inc., 59 Temple Place - Suite 330,
22    Boston, MA 02111-1307, USA.  */
23
24 #include "server.h"
25
26 const char *breakpoint_data;
27 int breakpoint_len;
28
29 #define MAX_BREAKPOINT_LEN 8
30
31 struct 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
49 struct breakpoint *breakpoints;
50
51 void
52 set_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
74 static void
75 delete_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
102 static struct breakpoint *
103 find_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
117 static void
118 reinsert_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
136 void
137 reinsert_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
143   orig_bp = find_breakpoint_at (stop_pc);
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
157 void
158 uninsert_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
171 void
172 reinsert_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
187 int
188 check_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
205 void
206 set_breakpoint_data (const char *bp_data, int bp_len)
207 {
208   breakpoint_data = bp_data;
209   breakpoint_len = bp_len;
210 }
211
212 void
213 check_mem_read (CORE_ADDR mem_addr, char *buf, int mem_len)
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
245 void
246 check_mem_write (CORE_ADDR mem_addr, char *buf, int mem_len)
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 }