2 * Copyright (c) 2000 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@
28 * Revision 1.1.1.1 1998/09/22 21:05:48 wsanchez
29 * Import of Mac OS X kernel (~semeria)
31 * Revision 1.1.1.1 1998/03/07 02:26:09 wsanchez
32 * Import of OSF Mach kernel (~mburg)
34 * Revision 1.1.12.2 1995/01/06 19:11:06 devrcs
35 * mk6 CR668 - 1.3b26 merge
36 * * Revision 1.1.3.5 1994/05/06 18:40:29 tmt
37 * Merged osc1.3dec/shared with osc1.3b19
38 * Merge Alpha changes into osc1.312b source code.
41 * [1994/11/04 08:50:16 dwm]
43 * Revision 1.1.12.1 1994/09/23 01:22:53 ezf
44 * change marker to not FREE
45 * [1994/09/22 21:11:33 ezf]
47 * Revision 1.1.10.1 1994/01/05 19:28:22 bolinger
48 * Be sure to count kernel-loaded tasks as part of kernel address space
49 * in locating watchpoints.
50 * [1994/01/04 17:43:33 bolinger]
52 * Revision 1.1.3.3 1993/07/27 18:28:31 elliston
53 * Add ANSI prototypes. CR #9523.
54 * [1993/07/27 18:13:30 elliston]
56 * Revision 1.1.3.2 1993/06/02 23:13:14 jeffc
57 * Added to OSF/1 R1.3 from NMK15.0.
58 * [1993/06/02 20:57:54 jeffc]
60 * Revision 1.1 1992/09/30 02:01:33 robert
67 * Revision 2.7 91/10/09 16:04:32 af
68 * Revision 2.6.3.1 91/10/05 13:08:50 jeffreyh
69 * Added user space watch point support including non current task.
70 * Changed "map" field of db_watchpoint structure to "task"
71 * for a user to easily understand the target space.
74 * Revision 2.6.3.1 91/10/05 13:08:50 jeffreyh
75 * Added user space watch point support including non current task.
76 * Changed "map" field of db_watchpoint structure to "task"
77 * for a user to easily understand the target space.
80 * Revision 2.6 91/05/14 15:37:30 mrt
81 * Correcting copyright
83 * Revision 2.5 91/02/05 17:07:27 mrt
84 * Changed to new Mach copyright
85 * [91/01/31 16:20:02 mrt]
87 * Revision 2.4 91/01/08 15:09:24 rpd
88 * Use db_map_equal, db_map_current, db_map_addr.
91 * Revision 2.3 90/11/05 14:26:39 rpd
92 * Initialize db_watchpoints_inserted to TRUE.
95 * Revision 2.2 90/10/25 14:44:16 rwd
96 * Made db_watchpoint_cmd parse a size argument.
98 * Generalized the watchpoint support.
106 * Mach Operating System
107 * Copyright (c) 1991,1990 Carnegie Mellon University
108 * All Rights Reserved.
110 * Permission to use, copy, modify and distribute this software and its
111 * documentation is hereby granted, provided that both the copyright
112 * notice and this permission notice appear in all copies of the
113 * software, derivative works or modified versions, and any portions
114 * thereof, and that both notices appear in supporting documentation.
116 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
117 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
118 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
120 * Carnegie Mellon requests users of this software to return to
122 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
123 * School of Computer Science
124 * Carnegie Mellon University
125 * Pittsburgh PA 15213-3890
127 * any improvements or extensions that they make and grant Carnegie Mellon
128 * the rights to redistribute these changes.
133 * Author: Richard P. Draves, Carnegie Mellon University
137 #include <mach/boolean.h>
138 #include <mach/vm_param.h>
139 #include <mach/machine/vm_types.h>
140 #include <mach/machine/vm_param.h>
141 #include <vm/vm_map.h>
143 #include <machine/db_machdep.h>
144 #include <ddb/db_lex.h>
145 #include <ddb/db_watch.h>
146 #include <ddb/db_access.h>
147 #include <ddb/db_sym.h>
148 #include <ddb/db_task_thread.h>
149 #include <ddb/db_command.h>
150 #include <ddb/db_expr.h>
151 #include <ddb/db_output.h> /* For db_printf() */
152 #include <ddb/db_run.h> /* For db_single_step() */
158 boolean_t db_watchpoints_inserted
= TRUE
;
160 #define NWATCHPOINTS 100
161 struct db_watchpoint db_watch_table
[NWATCHPOINTS
];
162 db_watchpoint_t db_next_free_watchpoint
= &db_watch_table
[0];
163 db_watchpoint_t db_free_watchpoints
= 0;
164 db_watchpoint_t db_watchpoint_list
= 0;
166 extern vm_map_t kernel_map
;
170 /* Prototypes for functions local to this file. XXX -- should be static.
173 db_watchpoint_t
db_watchpoint_alloc(void);
175 void db_watchpoint_free(register db_watchpoint_t watch
);
177 void db_set_watchpoint(
182 void db_delete_watchpoint(
186 static int db_get_task(
191 void db_list_watchpoints(void);
196 db_watchpoint_alloc(void)
198 register db_watchpoint_t watch
;
200 if ((watch
= db_free_watchpoints
) != 0) {
201 db_free_watchpoints
= watch
->link
;
204 if (db_next_free_watchpoint
== &db_watch_table
[NWATCHPOINTS
]) {
205 db_printf("All watchpoints used.\n");
208 watch
= db_next_free_watchpoint
;
209 db_next_free_watchpoint
++;
215 db_watchpoint_free(register db_watchpoint_t watch
)
217 watch
->link
= db_free_watchpoints
;
218 db_free_watchpoints
= watch
;
227 register db_watchpoint_t watch
;
230 * Should we do anything fancy with overlapping regions?
233 for (watch
= db_watchpoint_list
; watch
!= 0; watch
= watch
->link
) {
234 if (watch
->task
== task
&&
235 (watch
->loaddr
== addr
) &&
236 (watch
->hiaddr
== addr
+size
)) {
237 db_printf("Already set.\n");
242 watch
= db_watchpoint_alloc();
244 db_printf("Too many watchpoints.\n");
249 watch
->loaddr
= addr
;
250 watch
->hiaddr
= addr
+size
;
252 watch
->link
= db_watchpoint_list
;
253 db_watchpoint_list
= watch
;
255 db_watchpoints_inserted
= FALSE
;
259 db_delete_watchpoint(
263 register db_watchpoint_t watch
;
264 register db_watchpoint_t
*prev
;
266 for (prev
= &db_watchpoint_list
; (watch
= *prev
) != 0;
267 prev
= &watch
->link
) {
268 if (watch
->task
== task
&&
269 (watch
->loaddr
<= addr
) &&
270 (addr
< watch
->hiaddr
)) {
272 db_watchpoint_free(watch
);
277 db_printf("Not set.\n");
281 db_list_watchpoints(void)
283 register db_watchpoint_t watch
;
286 if (db_watchpoint_list
== 0) {
287 db_printf("No watchpoints set\n");
291 db_printf("Space Address Size\n");
292 for (watch
= db_watchpoint_list
; watch
!= 0; watch
= watch
->link
) {
293 if (watch
->task
== TASK_NULL
)
294 db_printf("kernel ");
296 task_id
= db_lookup_task(watch
->task
);
298 db_printf("%*X", 2*sizeof(vm_offset_t
), watch
->task
);
300 db_printf("task%-3d ", task_id
);
302 db_printf(" %*X %X\n", 2*sizeof(vm_offset_t
), watch
->loaddr
,
303 watch
->hiaddr
- watch
->loaddr
);
313 task_t task
= TASK_NULL
;
315 boolean_t user_space
;
317 user_space
= db_option(modif
, 'T');
319 if (db_expression(&value
)) {
320 task
= (task_t
)value
;
321 if (db_lookup_task(task
) < 0) {
322 db_printf("bad task address %X\n", task
);
326 task
= db_default_task
;
327 if (task
== TASK_NULL
) {
328 if ((task
= db_current_task()) == TASK_NULL
) {
329 db_printf("no task\n");
335 if (!DB_VALID_ADDRESS(addr
, user_space
)) {
336 db_printf("Address %#X is not in %s space\n", addr
,
337 (user_space
)? "user": "kernel");
344 /* Delete watchpoint */
354 if (db_get_task(modif
, &task
, addr
) < 0)
356 db_delete_watchpoint(task
, addr
);
371 if (db_get_task(modif
, &task
, addr
) < 0)
373 if (db_expression(&value
))
374 size
= (vm_size_t
) value
;
377 db_set_watchpoint(task
, addr
, size
);
380 /* list watchpoints */
382 db_listwatch_cmd(void)
384 db_list_watchpoints();
388 db_set_watchpoints(void)
390 register db_watchpoint_t watch
;
393 if (!db_watchpoints_inserted
) {
394 for (watch
= db_watchpoint_list
; watch
!= 0; watch
= watch
->link
) {
395 map
= (watch
->task
)? watch
->task
->map
: kernel_map
;
396 pmap_protect(map
->pmap
,
397 trunc_page(watch
->loaddr
),
398 round_page(watch
->hiaddr
),
401 db_watchpoints_inserted
= TRUE
;
406 db_clear_watchpoints(void)
408 db_watchpoints_inserted
= FALSE
;
417 register db_watchpoint_t watch
;
418 db_watchpoint_t found
= 0;
419 register task_t task_space
;
421 task_space
= (vm_map_pmap(map
) == kernel_pmap
)?
422 TASK_NULL
: db_current_space();
423 for (watch
= db_watchpoint_list
; watch
!= 0; watch
= watch
->link
) {
424 if (watch
->task
== task_space
) {
425 if ((watch
->loaddr
<= addr
) && (addr
< watch
->hiaddr
))
427 else if ((trunc_page(watch
->loaddr
) <= addr
) &&
428 (addr
< round_page(watch
->hiaddr
)))
434 * We didn't hit exactly on a watchpoint, but we are
435 * in a protected region. We want to single-step
436 * and then re-protect.
440 db_watchpoints_inserted
= FALSE
;
441 db_single_step(regs
, task_space
);