2 * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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.
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
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
20 * @APPLE_LICENSE_HEADER_END@
26 * Mach Operating System
27 * Copyright (c) 1991,1990 Carnegie Mellon University
28 * All Rights Reserved.
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.
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.
40 * Carnegie Mellon requests users of this software to return to
42 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
43 * School of Computer Science
44 * Carnegie Mellon University
45 * Pittsburgh PA 15213-3890
47 * any improvements or extensions that they make and grant Carnegie Mellon
48 * the rights to redistribute these changes.
53 * Author: Richard P. Draves, Carnegie Mellon University
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>
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() */
78 boolean_t db_watchpoints_inserted
= TRUE
;
80 #define NWATCHPOINTS 100
81 struct db_watchpoint db_watch_table
[NWATCHPOINTS
];
82 db_watchpoint_t db_next_free_watchpoint
= &db_watch_table
[0];
83 db_watchpoint_t db_free_watchpoints
= 0;
84 db_watchpoint_t db_watchpoint_list
= 0;
86 extern vm_map_t kernel_map
;
90 /* Prototypes for functions local to this file. XXX -- should be static.
93 db_watchpoint_t
db_watchpoint_alloc(void);
95 void db_watchpoint_free(register db_watchpoint_t watch
);
97 void db_set_watchpoint(
102 void db_delete_watchpoint(
106 static int db_get_task(
111 void db_list_watchpoints(void);
116 db_watchpoint_alloc(void)
118 register db_watchpoint_t watch
;
120 if ((watch
= db_free_watchpoints
) != 0) {
121 db_free_watchpoints
= watch
->link
;
124 if (db_next_free_watchpoint
== &db_watch_table
[NWATCHPOINTS
]) {
125 db_printf("All watchpoints used.\n");
128 watch
= db_next_free_watchpoint
;
129 db_next_free_watchpoint
++;
135 db_watchpoint_free(register db_watchpoint_t watch
)
137 watch
->link
= db_free_watchpoints
;
138 db_free_watchpoints
= watch
;
147 register db_watchpoint_t watch
;
150 * Should we do anything fancy with overlapping regions?
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");
162 watch
= db_watchpoint_alloc();
164 db_printf("Too many watchpoints.\n");
169 watch
->loaddr
= addr
;
170 watch
->hiaddr
= addr
+size
;
172 watch
->link
= db_watchpoint_list
;
173 db_watchpoint_list
= watch
;
175 db_watchpoints_inserted
= FALSE
;
179 db_delete_watchpoint(
183 register db_watchpoint_t watch
;
184 register db_watchpoint_t
*prev
;
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
)) {
192 db_watchpoint_free(watch
);
197 db_printf("Not set.\n");
201 db_list_watchpoints(void)
203 register db_watchpoint_t watch
;
206 if (db_watchpoint_list
== 0) {
207 db_printf("No watchpoints set\n");
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 ");
216 task_id
= db_lookup_task(watch
->task
);
218 db_printf("%*X", 2*sizeof(vm_offset_t
), watch
->task
);
220 db_printf("task%-3d ", task_id
);
222 db_printf(" %*X %X\n", 2*sizeof(vm_offset_t
), watch
->loaddr
,
223 watch
->hiaddr
- watch
->loaddr
);
233 task_t task
= TASK_NULL
;
235 boolean_t user_space
;
237 user_space
= db_option(modif
, 'T');
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
);
246 task
= db_default_task
;
247 if (task
== TASK_NULL
) {
248 if ((task
= db_current_task()) == TASK_NULL
) {
249 db_printf("no task\n");
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");
264 /* Delete watchpoint */
274 if (db_get_task(modif
, &task
, addr
) < 0)
276 db_delete_watchpoint(task
, addr
);
291 if (db_get_task(modif
, &task
, addr
) < 0)
293 if (db_expression(&value
))
294 size
= (vm_size_t
) value
;
297 db_set_watchpoint(task
, addr
, size
);
300 /* list watchpoints */
302 db_listwatch_cmd(void)
304 db_list_watchpoints();
308 db_set_watchpoints(void)
310 register db_watchpoint_t watch
;
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 vm_map_trunc_page(watch
->loaddr
),
318 vm_map_round_page(watch
->hiaddr
),
321 db_watchpoints_inserted
= TRUE
;
326 db_clear_watchpoints(void)
328 db_watchpoints_inserted
= FALSE
;
337 register db_watchpoint_t watch
;
338 db_watchpoint_t found
= 0;
339 register task_t task_space
;
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
))
347 else if ((trunc_page(watch
->loaddr
) <= addr
) &&
348 (addr
< round_page(watch
->hiaddr
)))
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.
360 db_watchpoints_inserted
= FALSE
;
361 db_single_step(regs
, task_space
);