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