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