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