]> git.saurik.com Git - apple/xnu.git/blame - osfmk/ddb/db_watch.c
xnu-792.25.20.tar.gz
[apple/xnu.git] / osfmk / ddb / db_watch.c
CommitLineData
1c79356b 1/*
91447636 2 * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved.
1c79356b 3 *
6601e61a 4 * @APPLE_LICENSE_HEADER_START@
1c79356b 5 *
6601e61a
A
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
8f6c56a5 11 *
6601e61a
A
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
8f6c56a5
A
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
6601e61a
A
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
8f6c56a5 19 *
6601e61a 20 * @APPLE_LICENSE_HEADER_END@
1c79356b
A
21 */
22/*
23 * @OSF_COPYRIGHT@
24 */
1c79356b
A
25/*
26 * Mach Operating System
27 * Copyright (c) 1991,1990 Carnegie Mellon University
28 * All Rights Reserved.
29 *
30 * Permission to use, copy, modify and distribute this software and its
31 * documentation is hereby granted, provided that both the copyright
32 * notice and this permission notice appear in all copies of the
33 * software, derivative works or modified versions, and any portions
34 * thereof, and that both notices appear in supporting documentation.
35 *
36 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
37 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
38 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
39 *
40 * Carnegie Mellon requests users of this software to return to
41 *
42 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
43 * School of Computer Science
44 * Carnegie Mellon University
45 * Pittsburgh PA 15213-3890
46 *
47 * any improvements or extensions that they make and grant Carnegie Mellon
48 * the rights to redistribute these changes.
49 */
50/*
51 */
52/*
53 * Author: Richard P. Draves, Carnegie Mellon University
54 * Date: 10/90
55 */
56
57#include <mach/boolean.h>
58#include <mach/vm_param.h>
59#include <mach/machine/vm_types.h>
60#include <mach/machine/vm_param.h>
61#include <vm/vm_map.h>
62
63#include <machine/db_machdep.h>
64#include <ddb/db_lex.h>
65#include <ddb/db_watch.h>
66#include <ddb/db_access.h>
67#include <ddb/db_sym.h>
68#include <ddb/db_task_thread.h>
69#include <ddb/db_command.h>
70#include <ddb/db_expr.h>
71#include <ddb/db_output.h> /* For db_printf() */
72#include <ddb/db_run.h> /* For db_single_step() */
73
74/*
75 * Watchpoints.
76 */
77
78boolean_t db_watchpoints_inserted = TRUE;
79
80#define NWATCHPOINTS 100
81struct db_watchpoint db_watch_table[NWATCHPOINTS];
82db_watchpoint_t db_next_free_watchpoint = &db_watch_table[0];
83db_watchpoint_t db_free_watchpoints = 0;
84db_watchpoint_t db_watchpoint_list = 0;
85
86extern vm_map_t kernel_map;
87
88
89
90/* Prototypes for functions local to this file. XXX -- should be static.
91 */
92
93db_watchpoint_t db_watchpoint_alloc(void);
94
95void db_watchpoint_free(register db_watchpoint_t watch);
96
97void db_set_watchpoint(
98 task_t task,
99 db_addr_t addr,
100 vm_size_t size);
101
102void db_delete_watchpoint(
103 task_t task,
104 db_addr_t addr);
105
106static int db_get_task(
107 char *modif,
108 task_t *taskp,
109 db_addr_t addr);
110
111void db_list_watchpoints(void);
112
113
114
115db_watchpoint_t
116db_watchpoint_alloc(void)
117{
118 register db_watchpoint_t watch;
119
120 if ((watch = db_free_watchpoints) != 0) {
121 db_free_watchpoints = watch->link;
122 return (watch);
123 }
124 if (db_next_free_watchpoint == &db_watch_table[NWATCHPOINTS]) {
125 db_printf("All watchpoints used.\n");
126 return (0);
127 }
128 watch = db_next_free_watchpoint;
129 db_next_free_watchpoint++;
130
131 return (watch);
132}
133
134void
135db_watchpoint_free(register db_watchpoint_t watch)
136{
137 watch->link = db_free_watchpoints;
138 db_free_watchpoints = watch;
139}
140
141void
142db_set_watchpoint(
143 task_t task,
144 db_addr_t addr,
145 vm_size_t size)
146{
147 register db_watchpoint_t watch;
148
149 /*
150 * Should we do anything fancy with overlapping regions?
151 */
152
153 for (watch = db_watchpoint_list; watch != 0; watch = watch->link) {
154 if (watch->task == task &&
155 (watch->loaddr == addr) &&
156 (watch->hiaddr == addr+size)) {
157 db_printf("Already set.\n");
158 return;
159 }
160 }
161
162 watch = db_watchpoint_alloc();
163 if (watch == 0) {
164 db_printf("Too many watchpoints.\n");
165 return;
166 }
167
168 watch->task = task;
169 watch->loaddr = addr;
170 watch->hiaddr = addr+size;
171
172 watch->link = db_watchpoint_list;
173 db_watchpoint_list = watch;
174
175 db_watchpoints_inserted = FALSE;
176}
177
178void
179db_delete_watchpoint(
180 task_t task,
181 db_addr_t addr)
182{
183 register db_watchpoint_t watch;
184 register db_watchpoint_t *prev;
185
186 for (prev = &db_watchpoint_list; (watch = *prev) != 0;
187 prev = &watch->link) {
188 if (watch->task == task &&
189 (watch->loaddr <= addr) &&
190 (addr < watch->hiaddr)) {
191 *prev = watch->link;
192 db_watchpoint_free(watch);
193 return;
194 }
195 }
196
197 db_printf("Not set.\n");
198}
199
200void
201db_list_watchpoints(void)
202{
203 register db_watchpoint_t watch;
204 int task_id;
205
206 if (db_watchpoint_list == 0) {
207 db_printf("No watchpoints set\n");
208 return;
209 }
210
211 db_printf("Space Address Size\n");
212 for (watch = db_watchpoint_list; watch != 0; watch = watch->link) {
213 if (watch->task == TASK_NULL)
214 db_printf("kernel ");
215 else {
216 task_id = db_lookup_task(watch->task);
217 if (task_id < 0)
218 db_printf("%*X", 2*sizeof(vm_offset_t), watch->task);
219 else
220 db_printf("task%-3d ", task_id);
221 }
222 db_printf(" %*X %X\n", 2*sizeof(vm_offset_t), watch->loaddr,
223 watch->hiaddr - watch->loaddr);
224 }
225}
226
227static int
228db_get_task(
229 char *modif,
230 task_t *taskp,
231 db_addr_t addr)
232{
233 task_t task = TASK_NULL;
234 db_expr_t value;
235 boolean_t user_space;
236
237 user_space = db_option(modif, 'T');
238 if (user_space) {
239 if (db_expression(&value)) {
240 task = (task_t)value;
241 if (db_lookup_task(task) < 0) {
242 db_printf("bad task address %X\n", task);
243 return(-1);
244 }
245 } else {
246 task = db_default_task;
247 if (task == TASK_NULL) {
248 if ((task = db_current_task()) == TASK_NULL) {
249 db_printf("no task\n");
250 return(-1);
251 }
252 }
253 }
254 }
255 if (!DB_VALID_ADDRESS(addr, user_space)) {
256 db_printf("Address %#X is not in %s space\n", addr,
257 (user_space)? "user": "kernel");
258 return(-1);
259 }
260 *taskp = task;
261 return(0);
262}
263
264/* Delete watchpoint */
265void
266db_deletewatch_cmd(
267 db_expr_t addr,
268 int have_addr,
269 db_expr_t count,
270 char * modif)
271{
272 task_t task;
273
274 if (db_get_task(modif, &task, addr) < 0)
275 return;
276 db_delete_watchpoint(task, addr);
277}
278
279/* Set watchpoint */
280void
281db_watchpoint_cmd(
282 db_expr_t addr,
283 int have_addr,
284 db_expr_t count,
285 char * modif)
286{
287 vm_size_t size;
288 db_expr_t value;
289 task_t task;
290
291 if (db_get_task(modif, &task, addr) < 0)
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 */
301void
302db_listwatch_cmd(void)
303{
304 db_list_watchpoints();
305}
306
307void
308db_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,
91447636
A
317 vm_map_trunc_page(watch->loaddr),
318 vm_map_round_page(watch->hiaddr),
1c79356b
A
319 VM_PROT_READ);
320 }
321 db_watchpoints_inserted = TRUE;
322 }
323}
324
325void
326db_clear_watchpoints(void)
327{
328 db_watchpoints_inserted = FALSE;
329}
330
331boolean_t
332db_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 = (vm_map_pmap(map) == kernel_pmap)?
342 TASK_NULL: db_current_space();
343 for (watch = db_watchpoint_list; watch != 0; watch = watch->link) {
344 if (watch->task == task_space) {
345 if ((watch->loaddr <= addr) && (addr < watch->hiaddr))
346 return (TRUE);
91447636
A
347 else if ((trunc_page(watch->loaddr) <= addr) &&
348 (addr < round_page(watch->hiaddr)))
1c79356b
A
349 found = watch;
350 }
351 }
352
353 /*
354 * We didn't hit exactly on a watchpoint, but we are
355 * in a protected region. We want to single-step
356 * and then re-protect.
357 */
358
359 if (found) {
360 db_watchpoints_inserted = FALSE;
361 db_single_step(regs, task_space);
362 }
363
364 return (FALSE);
365}