1 | /* $NetBSD: db_watch.c,v 1.27 2007/02/22 06:41:01 thorpej 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 "AS IS" |
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@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/cdefs.h> |
33 | __KERNEL_RCSID(0, "$NetBSD: db_watch.c,v 1.27 2007/02/22 06:41:01 thorpej Exp $" ); |
34 | |
35 | #include <sys/param.h> |
36 | #include <sys/proc.h> |
37 | |
38 | #include <machine/db_machdep.h> |
39 | |
40 | #include <ddb/db_break.h> |
41 | #include <ddb/db_watch.h> |
42 | #include <ddb/db_lex.h> |
43 | #include <ddb/db_access.h> |
44 | #include <ddb/db_run.h> |
45 | #include <ddb/db_sym.h> |
46 | #include <ddb/db_output.h> |
47 | #include <ddb/db_command.h> |
48 | #include <ddb/db_extern.h> |
49 | |
50 | /* |
51 | * Watchpoints. |
52 | */ |
53 | |
54 | static bool db_watchpoints_inserted = true; |
55 | |
56 | #define NWATCHPOINTS 100 |
57 | static struct db_watchpoint db_watch_table[NWATCHPOINTS]; |
58 | static db_watchpoint_t db_next_free_watchpoint = &db_watch_table[0]; |
59 | static db_watchpoint_t db_free_watchpoints = 0; |
60 | static db_watchpoint_t db_watchpoint_list = 0; |
61 | |
62 | static void db_delete_watchpoint(struct vm_map *, db_addr_t); |
63 | static void db_list_watchpoints(void); |
64 | static void db_set_watchpoint(struct vm_map *, db_addr_t, vsize_t); |
65 | static db_watchpoint_t db_watchpoint_alloc(void); |
66 | static void db_watchpoint_free(db_watchpoint_t); |
67 | |
68 | db_watchpoint_t |
69 | db_watchpoint_alloc(void) |
70 | { |
71 | db_watchpoint_t watch; |
72 | |
73 | if ((watch = db_free_watchpoints) != 0) { |
74 | db_free_watchpoints = watch->link; |
75 | return (watch); |
76 | } |
77 | if (db_next_free_watchpoint == &db_watch_table[NWATCHPOINTS]) { |
78 | db_printf("All watchpoints used.\n" ); |
79 | return (0); |
80 | } |
81 | watch = db_next_free_watchpoint; |
82 | db_next_free_watchpoint++; |
83 | |
84 | return (watch); |
85 | } |
86 | |
87 | void |
88 | db_watchpoint_free(db_watchpoint_t watch) |
89 | { |
90 | watch->link = db_free_watchpoints; |
91 | db_free_watchpoints = watch; |
92 | } |
93 | |
94 | void |
95 | db_set_watchpoint(struct vm_map *map, db_addr_t addr, vsize_t size) |
96 | { |
97 | db_watchpoint_t watch; |
98 | |
99 | if (map == NULL) { |
100 | db_printf("No map.\n" ); |
101 | return; |
102 | } |
103 | |
104 | /* |
105 | * Should we do anything fancy with overlapping regions? |
106 | */ |
107 | |
108 | for (watch = db_watchpoint_list; watch != 0; watch = watch->link) |
109 | if (db_map_equal(watch->map, map) && |
110 | (watch->loaddr == addr) && |
111 | (watch->hiaddr == addr+size)) { |
112 | db_printf("Already set.\n" ); |
113 | return; |
114 | } |
115 | |
116 | watch = db_watchpoint_alloc(); |
117 | if (watch == 0) { |
118 | db_printf("Too many watchpoints.\n" ); |
119 | return; |
120 | } |
121 | |
122 | watch->map = map; |
123 | watch->loaddr = addr; |
124 | watch->hiaddr = addr+size; |
125 | |
126 | watch->link = db_watchpoint_list; |
127 | db_watchpoint_list = watch; |
128 | |
129 | db_watchpoints_inserted = false; |
130 | } |
131 | |
132 | static void |
133 | db_delete_watchpoint(struct vm_map *map, db_addr_t addr) |
134 | { |
135 | db_watchpoint_t watch; |
136 | 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(void) |
154 | { |
155 | 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; watch != 0; watch = watch->link) |
164 | db_printf("%s%p %8lx %lx\n" , |
165 | db_map_current(watch->map) ? "*" : " " , |
166 | watch->map, (long)watch->loaddr, |
167 | (long)(watch->hiaddr - watch->loaddr)); |
168 | } |
169 | |
170 | /* Delete watchpoint */ |
171 | /*ARGSUSED*/ |
172 | void |
173 | db_deletewatch_cmd(db_expr_t addr, bool have_addr, |
174 | db_expr_t count, const char *modif) |
175 | { |
176 | |
177 | db_delete_watchpoint(db_map_addr(addr), addr); |
178 | } |
179 | |
180 | /* Set watchpoint */ |
181 | /*ARGSUSED*/ |
182 | void |
183 | db_watchpoint_cmd(db_expr_t addr, bool have_addr, |
184 | db_expr_t count, const char *modif) |
185 | { |
186 | vsize_t size; |
187 | db_expr_t value; |
188 | |
189 | if (db_expression(&value)) |
190 | size = (vsize_t) value; |
191 | else |
192 | size = 4; |
193 | db_skip_to_eol(); |
194 | |
195 | db_set_watchpoint(db_map_addr(addr), addr, size); |
196 | } |
197 | |
198 | /* list watchpoints */ |
199 | /*ARGSUSED*/ |
200 | void |
201 | db_listwatch_cmd(db_expr_t addr, bool have_addr, |
202 | db_expr_t count, const char *modif) |
203 | { |
204 | |
205 | db_list_watchpoints(); |
206 | } |
207 | |
208 | void |
209 | db_set_watchpoints(void) |
210 | { |
211 | db_watchpoint_t watch; |
212 | |
213 | if (!db_watchpoints_inserted) { |
214 | for (watch = db_watchpoint_list; |
215 | watch != 0; |
216 | watch = watch->link) { |
217 | pmap_protect(watch->map->pmap, |
218 | trunc_page(watch->loaddr), |
219 | round_page(watch->hiaddr), |
220 | VM_PROT_READ); |
221 | pmap_update(watch->map->pmap); |
222 | } |
223 | |
224 | db_watchpoints_inserted = true; |
225 | } |
226 | } |
227 | |
228 | void |
229 | db_clear_watchpoints(void) |
230 | { |
231 | |
232 | db_watchpoints_inserted = false; |
233 | } |
234 | |