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