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