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