2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
23 * @APPLE_LICENSE_HEADER_END@
31 * Revision 1.1.1.1 1998/09/22 21:05:48 wsanchez
32 * Import of Mac OS X kernel (~semeria)
34 * Revision 1.1.1.1 1998/03/07 02:26:09 wsanchez
35 * Import of OSF Mach kernel (~mburg)
37 * Revision 1.1.12.2 1995/01/06 19:11:06 devrcs
38 * mk6 CR668 - 1.3b26 merge
39 * * Revision 1.1.3.5 1994/05/06 18:40:29 tmt
40 * Merged osc1.3dec/shared with osc1.3b19
41 * Merge Alpha changes into osc1.312b source code.
44 * [1994/11/04 08:50:16 dwm]
46 * Revision 1.1.12.1 1994/09/23 01:22:53 ezf
47 * change marker to not FREE
48 * [1994/09/22 21:11:33 ezf]
50 * Revision 1.1.10.1 1994/01/05 19:28:22 bolinger
51 * Be sure to count kernel-loaded tasks as part of kernel address space
52 * in locating watchpoints.
53 * [1994/01/04 17:43:33 bolinger]
55 * Revision 1.1.3.3 1993/07/27 18:28:31 elliston
56 * Add ANSI prototypes. CR #9523.
57 * [1993/07/27 18:13:30 elliston]
59 * Revision 1.1.3.2 1993/06/02 23:13:14 jeffc
60 * Added to OSF/1 R1.3 from NMK15.0.
61 * [1993/06/02 20:57:54 jeffc]
63 * Revision 1.1 1992/09/30 02:01:33 robert
70 * Revision 2.7 91/10/09 16:04:32 af
71 * Revision 2.6.3.1 91/10/05 13:08:50 jeffreyh
72 * Added user space watch point support including non current task.
73 * Changed "map" field of db_watchpoint structure to "task"
74 * for a user to easily understand the target space.
77 * Revision 2.6.3.1 91/10/05 13:08:50 jeffreyh
78 * Added user space watch point support including non current task.
79 * Changed "map" field of db_watchpoint structure to "task"
80 * for a user to easily understand the target space.
83 * Revision 2.6 91/05/14 15:37:30 mrt
84 * Correcting copyright
86 * Revision 2.5 91/02/05 17:07:27 mrt
87 * Changed to new Mach copyright
88 * [91/01/31 16:20:02 mrt]
90 * Revision 2.4 91/01/08 15:09:24 rpd
91 * Use db_map_equal, db_map_current, db_map_addr.
94 * Revision 2.3 90/11/05 14:26:39 rpd
95 * Initialize db_watchpoints_inserted to TRUE.
98 * Revision 2.2 90/10/25 14:44:16 rwd
99 * Made db_watchpoint_cmd parse a size argument.
101 * Generalized the watchpoint support.
109 * Mach Operating System
110 * Copyright (c) 1991,1990 Carnegie Mellon University
111 * All Rights Reserved.
113 * Permission to use, copy, modify and distribute this software and its
114 * documentation is hereby granted, provided that both the copyright
115 * notice and this permission notice appear in all copies of the
116 * software, derivative works or modified versions, and any portions
117 * thereof, and that both notices appear in supporting documentation.
119 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
120 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
121 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
123 * Carnegie Mellon requests users of this software to return to
125 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
126 * School of Computer Science
127 * Carnegie Mellon University
128 * Pittsburgh PA 15213-3890
130 * any improvements or extensions that they make and grant Carnegie Mellon
131 * the rights to redistribute these changes.
136 * Author: Richard P. Draves, Carnegie Mellon University
140 #include <mach/boolean.h>
141 #include <mach/vm_param.h>
142 #include <mach/machine/vm_types.h>
143 #include <mach/machine/vm_param.h>
144 #include <vm/vm_map.h>
146 #include <machine/db_machdep.h>
147 #include <ddb/db_lex.h>
148 #include <ddb/db_watch.h>
149 #include <ddb/db_access.h>
150 #include <ddb/db_sym.h>
151 #include <ddb/db_task_thread.h>
152 #include <ddb/db_command.h>
153 #include <ddb/db_expr.h>
154 #include <ddb/db_output.h> /* For db_printf() */
155 #include <ddb/db_run.h> /* For db_single_step() */
161 boolean_t db_watchpoints_inserted
= TRUE
;
163 #define NWATCHPOINTS 100
164 struct db_watchpoint db_watch_table
[NWATCHPOINTS
];
165 db_watchpoint_t db_next_free_watchpoint
= &db_watch_table
[0];
166 db_watchpoint_t db_free_watchpoints
= 0;
167 db_watchpoint_t db_watchpoint_list
= 0;
169 extern vm_map_t kernel_map
;
173 /* Prototypes for functions local to this file. XXX -- should be static.
176 db_watchpoint_t
db_watchpoint_alloc(void);
178 void db_watchpoint_free(register db_watchpoint_t watch
);
180 void db_set_watchpoint(
185 void db_delete_watchpoint(
189 static int db_get_task(
194 void db_list_watchpoints(void);
199 db_watchpoint_alloc(void)
201 register db_watchpoint_t watch
;
203 if ((watch
= db_free_watchpoints
) != 0) {
204 db_free_watchpoints
= watch
->link
;
207 if (db_next_free_watchpoint
== &db_watch_table
[NWATCHPOINTS
]) {
208 db_printf("All watchpoints used.\n");
211 watch
= db_next_free_watchpoint
;
212 db_next_free_watchpoint
++;
218 db_watchpoint_free(register db_watchpoint_t watch
)
220 watch
->link
= db_free_watchpoints
;
221 db_free_watchpoints
= watch
;
230 register db_watchpoint_t watch
;
233 * Should we do anything fancy with overlapping regions?
236 for (watch
= db_watchpoint_list
; watch
!= 0; watch
= watch
->link
) {
237 if (watch
->task
== task
&&
238 (watch
->loaddr
== addr
) &&
239 (watch
->hiaddr
== addr
+size
)) {
240 db_printf("Already set.\n");
245 watch
= db_watchpoint_alloc();
247 db_printf("Too many watchpoints.\n");
252 watch
->loaddr
= addr
;
253 watch
->hiaddr
= addr
+size
;
255 watch
->link
= db_watchpoint_list
;
256 db_watchpoint_list
= watch
;
258 db_watchpoints_inserted
= FALSE
;
262 db_delete_watchpoint(
266 register db_watchpoint_t watch
;
267 register db_watchpoint_t
*prev
;
269 for (prev
= &db_watchpoint_list
; (watch
= *prev
) != 0;
270 prev
= &watch
->link
) {
271 if (watch
->task
== task
&&
272 (watch
->loaddr
<= addr
) &&
273 (addr
< watch
->hiaddr
)) {
275 db_watchpoint_free(watch
);
280 db_printf("Not set.\n");
284 db_list_watchpoints(void)
286 register db_watchpoint_t watch
;
289 if (db_watchpoint_list
== 0) {
290 db_printf("No watchpoints set\n");
294 db_printf("Space Address Size\n");
295 for (watch
= db_watchpoint_list
; watch
!= 0; watch
= watch
->link
) {
296 if (watch
->task
== TASK_NULL
)
297 db_printf("kernel ");
299 task_id
= db_lookup_task(watch
->task
);
301 db_printf("%*X", 2*sizeof(vm_offset_t
), watch
->task
);
303 db_printf("task%-3d ", task_id
);
305 db_printf(" %*X %X\n", 2*sizeof(vm_offset_t
), watch
->loaddr
,
306 watch
->hiaddr
- watch
->loaddr
);
316 task_t task
= TASK_NULL
;
318 boolean_t user_space
;
320 user_space
= db_option(modif
, 'T');
322 if (db_expression(&value
)) {
323 task
= (task_t
)value
;
324 if (db_lookup_task(task
) < 0) {
325 db_printf("bad task address %X\n", task
);
329 task
= db_default_task
;
330 if (task
== TASK_NULL
) {
331 if ((task
= db_current_task()) == TASK_NULL
) {
332 db_printf("no task\n");
338 if (!DB_VALID_ADDRESS(addr
, user_space
)) {
339 db_printf("Address %#X is not in %s space\n", addr
,
340 (user_space
)? "user": "kernel");
347 /* Delete watchpoint */
357 if (db_get_task(modif
, &task
, addr
) < 0)
359 db_delete_watchpoint(task
, addr
);
374 if (db_get_task(modif
, &task
, addr
) < 0)
376 if (db_expression(&value
))
377 size
= (vm_size_t
) value
;
380 db_set_watchpoint(task
, addr
, size
);
383 /* list watchpoints */
385 db_listwatch_cmd(void)
387 db_list_watchpoints();
391 db_set_watchpoints(void)
393 register db_watchpoint_t watch
;
396 if (!db_watchpoints_inserted
) {
397 for (watch
= db_watchpoint_list
; watch
!= 0; watch
= watch
->link
) {
398 map
= (watch
->task
)? watch
->task
->map
: kernel_map
;
399 pmap_protect(map
->pmap
,
400 trunc_page(watch
->loaddr
),
401 round_page(watch
->hiaddr
),
404 db_watchpoints_inserted
= TRUE
;
409 db_clear_watchpoints(void)
411 db_watchpoints_inserted
= FALSE
;
420 register db_watchpoint_t watch
;
421 db_watchpoint_t found
= 0;
422 register task_t task_space
;
424 task_space
= (vm_map_pmap(map
) == kernel_pmap
)?
425 TASK_NULL
: db_current_space();
426 for (watch
= db_watchpoint_list
; watch
!= 0; watch
= watch
->link
) {
427 if (watch
->task
== task_space
) {
428 if ((watch
->loaddr
<= addr
) && (addr
< watch
->hiaddr
))
430 else if ((trunc_page(watch
->loaddr
) <= addr
) &&
431 (addr
< round_page(watch
->hiaddr
)))
437 * We didn't hit exactly on a watchpoint, but we are
438 * in a protected region. We want to single-step
439 * and then re-protect.
443 db_watchpoints_inserted
= FALSE
;
444 db_single_step(regs
, task_space
);