db_watch.c revision 12720
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 *	$Id: db_watch.c,v 1.9 1995/12/07 12:45:05 davidg Exp $
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#include <sys/proc.h>
37#include <vm/vm.h>
38#include <vm/vm_param.h>
39#include <vm/lock.h>
40#include <vm/vm_prot.h>
41#include <vm/pmap.h>
42#include <vm/vm_map.h>
43#include <ddb/ddb.h>
44
45#include <ddb/db_lex.h>
46#include <ddb/db_watch.h>
47#include <ddb/db_access.h>
48#include <ddb/db_sym.h>
49
50/*
51 * Watchpoints.
52 */
53
54static boolean_t	db_watchpoints_inserted = TRUE;
55
56#define	NWATCHPOINTS	100
57static struct db_watchpoint	db_watch_table[NWATCHPOINTS];
58static db_watchpoint_t	db_next_free_watchpoint = &db_watch_table[0];
59static db_watchpoint_t	db_free_watchpoints = 0;
60static db_watchpoint_t	db_watchpoint_list = 0;
61
62static db_watchpoint_t	db_watchpoint_alloc __P((void));
63static void		db_watchpoint_free __P((db_watchpoint_t watch));
64static void		db_delete_watchpoint __P((vm_map_t map,
65					db_addr_t addr));
66#ifdef notused
67static boolean_t	db_find_watchpoint __P((vm_map_t map, db_addr_t addr,
68					db_regs_t *regs));
69#endif
70static void		db_list_watchpoints __P((void));
71static void		db_set_watchpoint __P((vm_map_t map, db_addr_t addr,
72				       vm_size_t size));
73
74
75db_watchpoint_t
76db_watchpoint_alloc()
77{
78	register db_watchpoint_t	watch;
79
80	if ((watch = db_free_watchpoints) != 0) {
81	    db_free_watchpoints = watch->link;
82	    return (watch);
83	}
84	if (db_next_free_watchpoint == &db_watch_table[NWATCHPOINTS]) {
85	    db_printf("All watchpoints used.\n");
86	    return (0);
87	}
88	watch = db_next_free_watchpoint;
89	db_next_free_watchpoint++;
90
91	return (watch);
92}
93
94void
95db_watchpoint_free(watch)
96	register db_watchpoint_t	watch;
97{
98	watch->link = db_free_watchpoints;
99	db_free_watchpoints = watch;
100}
101
102static void
103db_set_watchpoint(map, addr, size)
104	vm_map_t	map;
105	db_addr_t	addr;
106	vm_size_t	size;
107{
108	register db_watchpoint_t	watch;
109
110	if (map == NULL) {
111	    db_printf("No map.\n");
112	    return;
113	}
114
115	/*
116	 *	Should we do anything fancy with overlapping regions?
117	 */
118
119	for (watch = db_watchpoint_list;
120	     watch != 0;
121	     watch = watch->link)
122	    if (db_map_equal(watch->map, map) &&
123		(watch->loaddr == addr) &&
124		(watch->hiaddr == addr+size)) {
125		db_printf("Already set.\n");
126		return;
127	    }
128
129	watch = db_watchpoint_alloc();
130	if (watch == 0) {
131	    db_printf("Too many watchpoints.\n");
132	    return;
133	}
134
135	watch->map = map;
136	watch->loaddr = addr;
137	watch->hiaddr = addr+size;
138
139	watch->link = db_watchpoint_list;
140	db_watchpoint_list = watch;
141
142	db_watchpoints_inserted = FALSE;
143}
144
145static void
146db_delete_watchpoint(map, addr)
147	vm_map_t	map;
148	db_addr_t	addr;
149{
150	register db_watchpoint_t	watch;
151	register db_watchpoint_t	*prev;
152
153	for (prev = &db_watchpoint_list;
154	     (watch = *prev) != 0;
155	     prev = &watch->link)
156	    if (db_map_equal(watch->map, map) &&
157		(watch->loaddr <= addr) &&
158		(addr < watch->hiaddr)) {
159		*prev = watch->link;
160		db_watchpoint_free(watch);
161		return;
162	    }
163
164	db_printf("Not set.\n");
165}
166
167static void
168db_list_watchpoints()
169{
170	register db_watchpoint_t	watch;
171
172	if (db_watchpoint_list == 0) {
173	    db_printf("No watchpoints set\n");
174	    return;
175	}
176
177	db_printf(" Map        Address  Size\n");
178	for (watch = db_watchpoint_list;
179	     watch != 0;
180	     watch = watch->link)
181	    db_printf("%s%8x  %8x  %x\n",
182		      db_map_current(watch->map) ? "*" : " ",
183		      watch->map, watch->loaddr,
184		      watch->hiaddr - watch->loaddr);
185}
186
187/* Delete watchpoint */
188/*ARGSUSED*/
189void
190db_deletewatch_cmd(addr, have_addr, count, modif)
191	db_expr_t	addr;
192	boolean_t	have_addr;
193	db_expr_t	count;
194	char *		modif;
195{
196	db_delete_watchpoint(db_map_addr(addr), addr);
197}
198
199/* Set watchpoint */
200/*ARGSUSED*/
201void
202db_watchpoint_cmd(addr, have_addr, count, modif)
203	db_expr_t	addr;
204	boolean_t	have_addr;
205	db_expr_t	count;
206	char *		modif;
207{
208	vm_size_t	size;
209	db_expr_t	value;
210
211	if (db_expression(&value))
212	    size = (vm_size_t) value;
213	else
214	    size = 4;
215	db_skip_to_eol();
216
217	db_set_watchpoint(db_map_addr(addr), addr, size);
218}
219
220/* list watchpoints */
221void
222db_listwatch_cmd(dummy1, dummy2, dummy3, dummy4)
223	db_expr_t	dummy1;
224	boolean_t	dummy2;
225	db_expr_t	dummy3;
226	char *		dummy4;
227{
228	db_list_watchpoints();
229}
230
231void
232db_set_watchpoints()
233{
234	register db_watchpoint_t	watch;
235
236	if (!db_watchpoints_inserted) {
237	    for (watch = db_watchpoint_list;
238	         watch != 0;
239	         watch = watch->link)
240		pmap_protect(watch->map->pmap,
241			     trunc_page(watch->loaddr),
242			     round_page(watch->hiaddr),
243			     VM_PROT_READ);
244
245	    db_watchpoints_inserted = TRUE;
246	}
247}
248
249void
250db_clear_watchpoints()
251{
252	db_watchpoints_inserted = FALSE;
253}
254
255#ifdef notused
256static boolean_t
257db_find_watchpoint(map, addr, regs)
258	vm_map_t	map;
259	db_addr_t	addr;
260	db_regs_t	*regs;
261{
262	register db_watchpoint_t watch;
263	db_watchpoint_t found = 0;
264
265	for (watch = db_watchpoint_list;
266	     watch != 0;
267	     watch = watch->link)
268	    if (db_map_equal(watch->map, map)) {
269		if ((watch->loaddr <= addr) &&
270		    (addr < watch->hiaddr))
271		    return (TRUE);
272		else if ((trunc_page(watch->loaddr) <= addr) &&
273			 (addr < round_page(watch->hiaddr)))
274		    found = watch;
275	    }
276
277	/*
278	 *	We didn't hit exactly on a watchpoint, but we are
279	 *	in a protected region.  We want to single-step
280	 *	and then re-protect.
281	 */
282
283	if (found) {
284	    db_watchpoints_inserted = FALSE;
285	    db_single_step(regs);
286	}
287
288	return (FALSE);
289}
290#endif
291