db_watch.c revision 22521
1/*
2 * Mach Operating System
3 * Copyright (c) 1991,1990 Carnegie Mellon University
4 * All Rights Reserved.
5 *
6 * Permission to use, copy, modify and distribute this software and its
7 * documentation is hereby granted, provided that both the copyright
8 * notice and this permission notice appear in all copies of the
9 * software, derivative works or modified versions, and any portions
10 * thereof, and that both notices appear in supporting documentation.
11 *
12 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
13 * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
14 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
15 *
16 * Carnegie Mellon requests users of this software to return to
17 *
18 *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
19 *  School of Computer Science
20 *  Carnegie Mellon University
21 *  Pittsburgh PA 15213-3890
22 *
23 * any improvements or extensions that they make and grant Carnegie the
24 * rights to redistribute these changes.
25 *
26 *	$FreeBSD: head/sys/ddb/db_watch.c 22521 1997-02-10 02:22:35Z dyson $
27 */
28
29/*
30 * 	Author: Richard P. Draves, Carnegie Mellon University
31 *	Date:	10/90
32 */
33
34#include <sys/param.h>
35#include <sys/systm.h>
36
37#include <vm/vm.h>
38#include <sys/lock.h>
39#include <vm/pmap.h>
40#include <vm/vm_map.h>
41#include <vm/vm_prot.h>
42
43#include <ddb/ddb.h>
44#include <ddb/db_lex.h>
45#include <ddb/db_watch.h>
46#include <ddb/db_access.h>
47#include <ddb/db_sym.h>
48
49/*
50 * Watchpoints.
51 */
52
53static boolean_t	db_watchpoints_inserted = TRUE;
54
55#define	NWATCHPOINTS	100
56static struct db_watchpoint	db_watch_table[NWATCHPOINTS];
57static db_watchpoint_t	db_next_free_watchpoint = &db_watch_table[0];
58static db_watchpoint_t	db_free_watchpoints = 0;
59static db_watchpoint_t	db_watchpoint_list = 0;
60
61static db_watchpoint_t	db_watchpoint_alloc __P((void));
62static void		db_watchpoint_free __P((db_watchpoint_t watch));
63static void		db_delete_watchpoint __P((vm_map_t map,
64					db_addr_t addr));
65#ifdef notused
66static boolean_t	db_find_watchpoint __P((vm_map_t map, db_addr_t addr,
67					db_regs_t *regs));
68#endif
69static void		db_list_watchpoints __P((void));
70static void		db_set_watchpoint __P((vm_map_t map, db_addr_t addr,
71				       vm_size_t size));
72
73
74db_watchpoint_t
75db_watchpoint_alloc()
76{
77	register db_watchpoint_t	watch;
78
79	if ((watch = db_free_watchpoints) != 0) {
80	    db_free_watchpoints = watch->link;
81	    return (watch);
82	}
83	if (db_next_free_watchpoint == &db_watch_table[NWATCHPOINTS]) {
84	    db_printf("All watchpoints used.\n");
85	    return (0);
86	}
87	watch = db_next_free_watchpoint;
88	db_next_free_watchpoint++;
89
90	return (watch);
91}
92
93void
94db_watchpoint_free(watch)
95	register db_watchpoint_t	watch;
96{
97	watch->link = db_free_watchpoints;
98	db_free_watchpoints = watch;
99}
100
101static void
102db_set_watchpoint(map, addr, size)
103	vm_map_t	map;
104	db_addr_t	addr;
105	vm_size_t	size;
106{
107	register db_watchpoint_t	watch;
108
109	if (map == NULL) {
110	    db_printf("No map.\n");
111	    return;
112	}
113
114	/*
115	 *	Should we do anything fancy with overlapping regions?
116	 */
117
118	for (watch = db_watchpoint_list;
119	     watch != 0;
120	     watch = watch->link)
121	    if (db_map_equal(watch->map, map) &&
122		(watch->loaddr == addr) &&
123		(watch->hiaddr == addr+size)) {
124		db_printf("Already set.\n");
125		return;
126	    }
127
128	watch = db_watchpoint_alloc();
129	if (watch == 0) {
130	    db_printf("Too many watchpoints.\n");
131	    return;
132	}
133
134	watch->map = map;
135	watch->loaddr = addr;
136	watch->hiaddr = addr+size;
137
138	watch->link = db_watchpoint_list;
139	db_watchpoint_list = watch;
140
141	db_watchpoints_inserted = FALSE;
142}
143
144static void
145db_delete_watchpoint(map, addr)
146	vm_map_t	map;
147	db_addr_t	addr;
148{
149	register db_watchpoint_t	watch;
150	register db_watchpoint_t	*prev;
151
152	for (prev = &db_watchpoint_list;
153	     (watch = *prev) != 0;
154	     prev = &watch->link)
155	    if (db_map_equal(watch->map, map) &&
156		(watch->loaddr <= addr) &&
157		(addr < watch->hiaddr)) {
158		*prev = watch->link;
159		db_watchpoint_free(watch);
160		return;
161	    }
162
163	db_printf("Not set.\n");
164}
165
166static void
167db_list_watchpoints()
168{
169	register db_watchpoint_t	watch;
170
171	if (db_watchpoint_list == 0) {
172	    db_printf("No watchpoints set\n");
173	    return;
174	}
175
176	db_printf(" Map        Address  Size\n");
177	for (watch = db_watchpoint_list;
178	     watch != 0;
179	     watch = watch->link)
180	    db_printf("%s%8x  %8x  %x\n",
181		      db_map_current(watch->map) ? "*" : " ",
182		      watch->map, watch->loaddr,
183		      watch->hiaddr - watch->loaddr);
184}
185
186/* Delete watchpoint */
187/*ARGSUSED*/
188void
189db_deletewatch_cmd(addr, have_addr, count, modif)
190	db_expr_t	addr;
191	boolean_t	have_addr;
192	db_expr_t	count;
193	char *		modif;
194{
195	db_delete_watchpoint(db_map_addr(addr), addr);
196}
197
198/* Set watchpoint */
199/*ARGSUSED*/
200void
201db_watchpoint_cmd(addr, have_addr, count, modif)
202	db_expr_t	addr;
203	boolean_t	have_addr;
204	db_expr_t	count;
205	char *		modif;
206{
207	vm_size_t	size;
208	db_expr_t	value;
209
210	if (db_expression(&value))
211	    size = (vm_size_t) value;
212	else
213	    size = 4;
214	db_skip_to_eol();
215
216	db_set_watchpoint(db_map_addr(addr), addr, size);
217}
218
219/* list watchpoints */
220void
221db_listwatch_cmd(dummy1, dummy2, dummy3, dummy4)
222	db_expr_t	dummy1;
223	boolean_t	dummy2;
224	db_expr_t	dummy3;
225	char *		dummy4;
226{
227	db_list_watchpoints();
228}
229
230void
231db_set_watchpoints()
232{
233	register db_watchpoint_t	watch;
234
235	if (!db_watchpoints_inserted) {
236	    for (watch = db_watchpoint_list;
237	         watch != 0;
238	         watch = watch->link)
239		pmap_protect(watch->map->pmap,
240			     trunc_page(watch->loaddr),
241			     round_page(watch->hiaddr),
242			     VM_PROT_READ);
243
244	    db_watchpoints_inserted = TRUE;
245	}
246}
247
248void
249db_clear_watchpoints()
250{
251	db_watchpoints_inserted = FALSE;
252}
253
254#ifdef notused
255static boolean_t
256db_find_watchpoint(map, addr, regs)
257	vm_map_t	map;
258	db_addr_t	addr;
259	db_regs_t	*regs;
260{
261	register db_watchpoint_t watch;
262	db_watchpoint_t found = 0;
263
264	for (watch = db_watchpoint_list;
265	     watch != 0;
266	     watch = watch->link)
267	    if (db_map_equal(watch->map, map)) {
268		if ((watch->loaddr <= addr) &&
269		    (addr < watch->hiaddr))
270		    return (TRUE);
271		else if ((trunc_page(watch->loaddr) <= addr) &&
272			 (addr < round_page(watch->hiaddr)))
273		    found = watch;
274	    }
275
276	/*
277	 *	We didn't hit exactly on a watchpoint, but we are
278	 *	in a protected region.  We want to single-step
279	 *	and then re-protect.
280	 */
281
282	if (found) {
283	    db_watchpoints_inserted = FALSE;
284	    db_single_step(regs);
285	}
286
287	return (FALSE);
288}
289#endif
290