FreeBSD/Linux Kernel Cross Reference
sys/ddb/db_watch.c
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 "AS IS"
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 Mellon
24 * the rights to redistribute these changes.
25 */
26 /*
27 * HISTORY
28 * $Log: db_watch.c,v $
29 * Revision 2.10 93/01/14 17:26:16 danner
30 * 64bit cleanup.
31 * [92/11/30 af]
32 *
33 * Revision 2.9 92/08/03 17:32:31 jfriedl
34 * removed silly prototypes
35 * [92/08/02 jfriedl]
36 *
37 * Revision 2.8 92/05/21 17:08:16 jfriedl
38 * tried prototypes.
39 * [92/05/20 jfriedl]
40 *
41 * Revision 2.7 91/10/09 16:04:32 af
42 * Added user space watch point support including non current task.
43 * Changed "map" field of db_watchpoint structure to "task"
44 * for a user to easily understand the target space.
45 * [91/08/29 tak]
46 *
47 * Revision 2.6 91/05/14 15:37:30 mrt
48 * Correcting copyright
49 *
50 * Revision 2.5 91/02/05 17:07:27 mrt
51 * Changed to new Mach copyright
52 * [91/01/31 16:20:02 mrt]
53 *
54 * Revision 2.4 91/01/08 15:09:24 rpd
55 * Use db_map_equal, db_map_current, db_map_addr.
56 * [90/11/10 rpd]
57 *
58 * Revision 2.3 90/11/05 14:26:39 rpd
59 * Initialize db_watchpoints_inserted to TRUE.
60 * [90/11/04 rpd]
61 *
62 * Revision 2.2 90/10/25 14:44:16 rwd
63 * Made db_watchpoint_cmd parse a size argument.
64 * [90/10/17 rpd]
65 * Generalized the watchpoint support.
66 * [90/10/16 rwd]
67 * Created.
68 * [90/10/16 rpd]
69 *
70 */
71 /*
72 * Author: Richard P. Draves, Carnegie Mellon University
73 * Date: 10/90
74 */
75
76 #include <mach/boolean.h>
77 #include <mach/vm_param.h>
78 #include <mach/machine/vm_types.h>
79 #include <mach/machine/vm_param.h>
80 #include <vm/vm_map.h>
81
82 #include <machine/db_machdep.h>
83 #include <ddb/db_lex.h>
84 #include <ddb/db_watch.h>
85 #include <ddb/db_access.h>
86 #include <ddb/db_sym.h>
87 #include <ddb/db_task_thread.h>
88
89
90
91 /*
92 * Watchpoints.
93 */
94
95 boolean_t db_watchpoints_inserted = TRUE;
96
97 #define NWATCHPOINTS 100
98 struct db_watchpoint db_watch_table[NWATCHPOINTS];
99 db_watchpoint_t db_next_free_watchpoint = &db_watch_table[0];
100 db_watchpoint_t db_free_watchpoints = 0;
101 db_watchpoint_t db_watchpoint_list = 0;
102
103 extern vm_map_t kernel_map;
104
105 db_watchpoint_t
106 db_watchpoint_alloc()
107 {
108 register db_watchpoint_t watch;
109
110 if ((watch = db_free_watchpoints) != 0) {
111 db_free_watchpoints = watch->link;
112 return (watch);
113 }
114 if (db_next_free_watchpoint == &db_watch_table[NWATCHPOINTS]) {
115 db_printf("All watchpoints used.\n");
116 return (0);
117 }
118 watch = db_next_free_watchpoint;
119 db_next_free_watchpoint++;
120
121 return (watch);
122 }
123
124 void
125 db_watchpoint_free(watch)
126 register db_watchpoint_t watch;
127 {
128 watch->link = db_free_watchpoints;
129 db_free_watchpoints = watch;
130 }
131
132 void
133 db_set_watchpoint(task, addr, size)
134 task_t task;
135 db_addr_t addr;
136 vm_size_t size;
137 {
138 register db_watchpoint_t watch;
139
140 /*
141 * Should we do anything fancy with overlapping regions?
142 */
143
144 for (watch = db_watchpoint_list; watch != 0; watch = watch->link) {
145 if (watch->task == task &&
146 (watch->loaddr == addr) &&
147 (watch->hiaddr == addr+size)) {
148 db_printf("Already set.\n");
149 return;
150 }
151 }
152
153 watch = db_watchpoint_alloc();
154 if (watch == 0) {
155 db_printf("Too many watchpoints.\n");
156 return;
157 }
158
159 watch->task = task;
160 watch->loaddr = addr;
161 watch->hiaddr = addr+size;
162
163 watch->link = db_watchpoint_list;
164 db_watchpoint_list = watch;
165
166 db_watchpoints_inserted = FALSE;
167 }
168
169 void
170 db_delete_watchpoint(task, addr)
171 task_t task;
172 db_addr_t addr;
173 {
174 register db_watchpoint_t watch;
175 register db_watchpoint_t *prev;
176
177 for (prev = &db_watchpoint_list; (watch = *prev) != 0;
178 prev = &watch->link) {
179 if (watch->task == task &&
180 (watch->loaddr <= addr) &&
181 (addr < watch->hiaddr)) {
182 *prev = watch->link;
183 db_watchpoint_free(watch);
184 return;
185 }
186 }
187
188 db_printf("Not set.\n");
189 }
190
191 void
192 db_list_watchpoints()
193 {
194 register db_watchpoint_t watch;
195 int task_id;
196
197 if (db_watchpoint_list == 0) {
198 db_printf("No watchpoints set\n");
199 return;
200 }
201
202 db_printf("Space Address Size\n");
203 for (watch = db_watchpoint_list; watch != 0; watch = watch->link) {
204 if (watch->task == TASK_NULL)
205 db_printf("kernel ");
206 else {
207 task_id = db_lookup_task(watch->task);
208 if (task_id < 0)
209 db_printf("%*X", 2*sizeof(vm_offset_t), watch->task);
210 else
211 db_printf("task%-3d ", task_id);
212 }
213 db_printf(" %*X %X\n", 2*sizeof(vm_offset_t), watch->loaddr,
214 watch->hiaddr - watch->loaddr);
215 }
216 }
217
218 static int
219 db_get_task(modif, taskp, addr)
220 char *modif;
221 task_t *taskp;
222 db_addr_t addr;
223 {
224 task_t task = TASK_NULL;
225 db_expr_t value;
226 boolean_t user_space;
227
228 user_space = db_option(modif, 'T');
229 if (user_space) {
230 if (db_expression(&value)) {
231 task = (task_t)value;
232 if (db_lookup_task(task) < 0) {
233 db_printf("bad task address %X\n", task);
234 return(-1);
235 }
236 } else {
237 task = db_default_task;
238 if (task == TASK_NULL) {
239 if ((task = db_current_task()) == TASK_NULL) {
240 db_printf("no task\n");
241 return(-1);
242 }
243 }
244 }
245 }
246 if (!DB_VALID_ADDRESS(addr, user_space)) {
247 db_printf("Address %#X is not in %s space\n", addr,
248 (user_space)? "user": "kernel");
249 return(-1);
250 }
251 *taskp = task;
252 return(0);
253 }
254
255 /* Delete watchpoint */
256 /*ARGSUSED*/
257 void
258 db_deletewatch_cmd(addr, have_addr, count, modif)
259 db_expr_t addr;
260 int have_addr;
261 db_expr_t count;
262 char * modif;
263 {
264 task_t task;
265
266 if (db_get_task(modif, &task, addr) < 0)
267 return;
268 db_delete_watchpoint(task, addr);
269 }
270
271 /* Set watchpoint */
272 /*ARGSUSED*/
273 void
274 db_watchpoint_cmd(addr, have_addr, count, modif)
275 db_expr_t addr;
276 int have_addr;
277 db_expr_t count;
278 char * modif;
279 {
280 vm_size_t size;
281 db_expr_t value;
282 task_t task;
283 boolean_t db_option();
284
285 if (db_get_task(modif, &task, addr) < 0)
286 return;
287 if (db_expression(&value))
288 size = (vm_size_t) value;
289 else
290 size = sizeof(int);
291 db_set_watchpoint(task, addr, size);
292 }
293
294 /* list watchpoints */
295 void
296 db_listwatch_cmd()
297 {
298 db_list_watchpoints();
299 }
300
301 void
302 db_set_watchpoints()
303 {
304 register db_watchpoint_t watch;
305 vm_map_t map;
306
307 if (!db_watchpoints_inserted) {
308 for (watch = db_watchpoint_list; watch != 0; watch = watch->link) {
309 map = (watch->task)? watch->task->map: kernel_map;
310 pmap_protect(map->pmap,
311 trunc_page(watch->loaddr),
312 round_page(watch->hiaddr),
313 VM_PROT_READ);
314 }
315 db_watchpoints_inserted = TRUE;
316 }
317 }
318
319 void
320 db_clear_watchpoints()
321 {
322 db_watchpoints_inserted = FALSE;
323 }
324
325 boolean_t
326 db_find_watchpoint(map, addr, regs)
327 vm_map_t map;
328 db_addr_t addr;
329 db_regs_t *regs;
330 {
331 register db_watchpoint_t watch;
332 db_watchpoint_t found = 0;
333 register task_t task_space;
334
335 task_space = (map == kernel_map)? TASK_NULL: db_current_task();
336 for (watch = db_watchpoint_list; watch != 0; watch = watch->link) {
337 if (watch->task == task_space) {
338 if ((watch->loaddr <= addr) && (addr < watch->hiaddr))
339 return (TRUE);
340 else if ((trunc_page(watch->loaddr) <= addr) &&
341 (addr < round_page(watch->hiaddr)))
342 found = watch;
343 }
344 }
345
346 /*
347 * We didn't hit exactly on a watchpoint, but we are
348 * in a protected region. We want to single-step
349 * and then re-protect.
350 */
351
352 if (found) {
353 db_watchpoints_inserted = FALSE;
354 db_single_step(regs, task_space);
355 }
356
357 return (FALSE);
358 }
Cache object: 524ebe6985919c445b112651bcb4d574
|