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