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