xref: /freebsd/sys/ddb/db_watch.c (revision afe61c15161c324a7af299a9b8457aba5afc92db)
1 /*
2  * Mach Operating System
3  * Copyright (c) 1991,1990 Carnegie Mellon University
4  * All Rights Reserved.
5  *
6  * Permission to use, copy, modify and distribute this software and its
7  * documentation is hereby granted, provided that both the copyright
8  * notice and this permission notice appear in all copies of the
9  * software, derivative works or modified versions, and any portions
10  * thereof, and that both notices appear in supporting documentation.
11  *
12  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
13  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
14  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
15  *
16  * Carnegie Mellon requests users of this software to return to
17  *
18  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
19  *  School of Computer Science
20  *  Carnegie Mellon University
21  *  Pittsburgh PA 15213-3890
22  *
23  * any improvements or extensions that they make and grant Carnegie the
24  * rights to redistribute these changes.
25  *
26  *	$Id: db_watch.c,v 1.2 1993/10/16 16:47:32 rgrimes Exp $
27  */
28 
29 /*
30  * 	Author: Richard P. Draves, Carnegie Mellon University
31  *	Date:	10/90
32  */
33 
34 #include "param.h"
35 #include "systm.h"
36 #include "proc.h"
37 #include "ddb/ddb.h"
38 
39 #include <vm/vm_map.h>
40 #include <ddb/db_lex.h>
41 #include <ddb/db_watch.h>
42 #include <ddb/db_access.h>
43 #include <ddb/db_sym.h>
44 
45 /*
46  * Watchpoints.
47  */
48 
49 extern boolean_t db_map_equal();
50 extern boolean_t db_map_current();
51 extern vm_map_t db_map_addr();
52 
53 boolean_t	db_watchpoints_inserted = TRUE;
54 
55 #define	NWATCHPOINTS	100
56 struct db_watchpoint	db_watch_table[NWATCHPOINTS];
57 db_watchpoint_t		db_next_free_watchpoint = &db_watch_table[0];
58 db_watchpoint_t		db_free_watchpoints = 0;
59 db_watchpoint_t		db_watchpoint_list = 0;
60 
61 db_watchpoint_t
62 db_watchpoint_alloc()
63 {
64 	register db_watchpoint_t	watch;
65 
66 	if ((watch = db_free_watchpoints) != 0) {
67 	    db_free_watchpoints = watch->link;
68 	    return (watch);
69 	}
70 	if (db_next_free_watchpoint == &db_watch_table[NWATCHPOINTS]) {
71 	    db_printf("All watchpoints used.\n");
72 	    return (0);
73 	}
74 	watch = db_next_free_watchpoint;
75 	db_next_free_watchpoint++;
76 
77 	return (watch);
78 }
79 
80 void
81 db_watchpoint_free(watch)
82 	register db_watchpoint_t	watch;
83 {
84 	watch->link = db_free_watchpoints;
85 	db_free_watchpoints = watch;
86 }
87 
88 void
89 db_set_watchpoint(map, addr, size)
90 	vm_map_t	map;
91 	db_addr_t	addr;
92 	vm_size_t	size;
93 {
94 	register db_watchpoint_t	watch;
95 
96 	if (map == NULL) {
97 	    db_printf("No map.\n");
98 	    return;
99 	}
100 
101 	/*
102 	 *	Should we do anything fancy with overlapping regions?
103 	 */
104 
105 	for (watch = db_watchpoint_list;
106 	     watch != 0;
107 	     watch = watch->link)
108 	    if (db_map_equal(watch->map, map) &&
109 		(watch->loaddr == addr) &&
110 		(watch->hiaddr == addr+size)) {
111 		db_printf("Already set.\n");
112 		return;
113 	    }
114 
115 	watch = db_watchpoint_alloc();
116 	if (watch == 0) {
117 	    db_printf("Too many watchpoints.\n");
118 	    return;
119 	}
120 
121 	watch->map = map;
122 	watch->loaddr = addr;
123 	watch->hiaddr = addr+size;
124 
125 	watch->link = db_watchpoint_list;
126 	db_watchpoint_list = watch;
127 
128 	db_watchpoints_inserted = FALSE;
129 }
130 
131 void
132 db_delete_watchpoint(map, addr)
133 	vm_map_t	map;
134 	db_addr_t	addr;
135 {
136 	register db_watchpoint_t	watch;
137 	register db_watchpoint_t	*prev;
138 
139 	for (prev = &db_watchpoint_list;
140 	     (watch = *prev) != 0;
141 	     prev = &watch->link)
142 	    if (db_map_equal(watch->map, map) &&
143 		(watch->loaddr <= addr) &&
144 		(addr < watch->hiaddr)) {
145 		*prev = watch->link;
146 		db_watchpoint_free(watch);
147 		return;
148 	    }
149 
150 	db_printf("Not set.\n");
151 }
152 
153 void
154 db_list_watchpoints()
155 {
156 	register db_watchpoint_t	watch;
157 
158 	if (db_watchpoint_list == 0) {
159 	    db_printf("No watchpoints set\n");
160 	    return;
161 	}
162 
163 	db_printf(" Map        Address  Size\n");
164 	for (watch = db_watchpoint_list;
165 	     watch != 0;
166 	     watch = watch->link)
167 	    db_printf("%s%8x  %8x  %x\n",
168 		      db_map_current(watch->map) ? "*" : " ",
169 		      watch->map, watch->loaddr,
170 		      watch->hiaddr - watch->loaddr);
171 }
172 
173 /* Delete watchpoint */
174 /*ARGSUSED*/
175 void
176 db_deletewatch_cmd(addr, have_addr, count, modif)
177 	db_expr_t	addr;
178 	int		have_addr;
179 	db_expr_t	count;
180 	char *		modif;
181 {
182 	db_delete_watchpoint(db_map_addr(addr), addr);
183 }
184 
185 /* Set watchpoint */
186 /*ARGSUSED*/
187 void
188 db_watchpoint_cmd(addr, have_addr, count, modif)
189 	db_expr_t	addr;
190 	int		have_addr;
191 	db_expr_t	count;
192 	char *		modif;
193 {
194 	vm_size_t	size;
195 	db_expr_t	value;
196 
197 	if (db_expression(&value))
198 	    size = (vm_size_t) value;
199 	else
200 	    size = 4;
201 	db_skip_to_eol();
202 
203 	db_set_watchpoint(db_map_addr(addr), addr, size);
204 }
205 
206 /* list watchpoints */
207 void
208 db_listwatch_cmd(db_expr_t dummy1, int dummy2, db_expr_t dummy3, char *dummmy4)
209 {
210 	db_list_watchpoints();
211 }
212 
213 void
214 db_set_watchpoints()
215 {
216 	register db_watchpoint_t	watch;
217 
218 	if (!db_watchpoints_inserted) {
219 	    for (watch = db_watchpoint_list;
220 	         watch != 0;
221 	         watch = watch->link)
222 		pmap_protect(watch->map->pmap,
223 			     trunc_page(watch->loaddr),
224 			     round_page(watch->hiaddr),
225 			     VM_PROT_READ);
226 
227 	    db_watchpoints_inserted = TRUE;
228 	}
229 }
230 
231 void
232 db_clear_watchpoints()
233 {
234 	db_watchpoints_inserted = FALSE;
235 }
236 
237 boolean_t
238 db_find_watchpoint(map, addr, regs)
239 	vm_map_t	map;
240 	db_addr_t	addr;
241 	db_regs_t	*regs;
242 {
243 	register db_watchpoint_t watch;
244 	db_watchpoint_t found = 0;
245 
246 	for (watch = db_watchpoint_list;
247 	     watch != 0;
248 	     watch = watch->link)
249 	    if (db_map_equal(watch->map, map)) {
250 		if ((watch->loaddr <= addr) &&
251 		    (addr < watch->hiaddr))
252 		    return (TRUE);
253 		else if ((trunc_page(watch->loaddr) <= addr) &&
254 			 (addr < round_page(watch->hiaddr)))
255 		    found = watch;
256 	    }
257 
258 	/*
259 	 *	We didn't hit exactly on a watchpoint, but we are
260 	 *	in a protected region.  We want to single-step
261 	 *	and then re-protect.
262 	 */
263 
264 	if (found) {
265 	    db_watchpoints_inserted = FALSE;
266 	    db_single_step(regs);
267 	}
268 
269 	return (FALSE);
270 }
271