xref: /openbsd-src/sys/ddb/db_watch.c (revision d13be5d47e4149db2549a9828e244d59dbc43f15)
1 /*	$OpenBSD: db_watch.c,v 1.10 2010/11/27 19:59:11 miod Exp $ */
2 /*	$NetBSD: db_watch.c,v 1.9 1996/03/30 22:30:12 christos Exp $	*/
3 
4 /*
5  * Mach Operating System
6  * Copyright (c) 1993,1992,1991,1990 Carnegie Mellon University
7  * All Rights Reserved.
8  *
9  * Permission to use, copy, modify and distribute this software and its
10  * documentation is hereby granted, provided that both the copyright
11  * notice and this permission notice appear in all copies of the
12  * software, derivative works or modified versions, and any portions
13  * thereof, and that both notices appear in supporting documentation.
14  *
15  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
16  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
17  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
18  *
19  * Carnegie Mellon requests users of this software to return to
20  *
21  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
22  *  School of Computer Science
23  *  Carnegie Mellon University
24  *  Pittsburgh PA 15213-3890
25  *
26  * any improvements or extensions that they make and grant Carnegie Mellon
27  * the rights to redistribute these changes.
28  *
29  * 	Author: Richard P. Draves, Carnegie Mellon University
30  *	Date:	10/90
31  */
32 
33 #include <sys/param.h>
34 #include <sys/proc.h>
35 
36 #include <machine/db_machdep.h>
37 
38 #include <ddb/db_break.h>
39 #include <ddb/db_watch.h>
40 #include <ddb/db_lex.h>
41 #include <ddb/db_access.h>
42 #include <ddb/db_run.h>
43 #include <ddb/db_sym.h>
44 #include <ddb/db_output.h>
45 #include <ddb/db_command.h>
46 #include <ddb/db_extern.h>
47 
48 /*
49  * Watchpoints.
50  */
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(void)
62 {
63 	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(db_watchpoint_t watch)
81 {
82 	watch->link = db_free_watchpoints;
83 	db_free_watchpoints = watch;
84 }
85 
86 void
87 db_set_watchpoint(db_addr_t addr, vsize_t size)
88 {
89 	db_watchpoint_t	watch;
90 
91 	/*
92 	 *	Should we do anything fancy with overlapping regions?
93 	 */
94 
95 	for (watch = db_watchpoint_list; watch != 0; watch = watch->link)
96 		if (watch->loaddr == addr && watch->hiaddr == addr + size) {
97 			db_printf("Already set.\n");
98 			return;
99 		}
100 
101 	watch = db_watchpoint_alloc();
102 	if (watch == 0) {
103 		db_printf("Too many watchpoints.\n");
104 		return;
105 	}
106 
107 	watch->loaddr = addr;
108 	watch->hiaddr = addr+size;
109 
110 	watch->link = db_watchpoint_list;
111 	db_watchpoint_list = watch;
112 
113 	db_watchpoints_inserted = FALSE;
114 }
115 
116 void
117 db_delete_watchpoint(db_addr_t addr)
118 {
119 	db_watchpoint_t	watch;
120 	db_watchpoint_t	*prev;
121 
122 	for (prev = &db_watchpoint_list; (watch = *prev) != 0;
123 	   prev = &watch->link)
124 		if (watch->loaddr <= addr && addr < watch->hiaddr) {
125 			*prev = watch->link;
126 			db_watchpoint_free(watch);
127 			return;
128 		}
129 
130 	db_printf("Not set.\n");
131 }
132 
133 void
134 db_list_watchpoints(void)
135 {
136 	db_watchpoint_t	watch;
137 
138 	if (db_watchpoint_list == 0) {
139 	    db_printf("No watchpoints set\n");
140 	    return;
141 	}
142 
143 	db_printf("  Address  Size\n");
144 	for (watch = db_watchpoint_list; watch != 0; watch = watch->link)
145 		db_printf("%8lx  %lx\n",
146 		    watch->loaddr, watch->hiaddr - watch->loaddr);
147 }
148 
149 /* Delete watchpoint */
150 /*ARGSUSED*/
151 void
152 db_deletewatch_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif)
153 {
154 	db_delete_watchpoint(addr);
155 }
156 
157 /* Set watchpoint */
158 /*ARGSUSED*/
159 void
160 db_watchpoint_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif)
161 {
162 	vsize_t 	size;
163 	db_expr_t	value;
164 
165 	if (db_expression(&value))
166 	    size = (vsize_t) value;
167 	else
168 	    size = 4;
169 	db_skip_to_eol();
170 
171 	db_set_watchpoint(addr, size);
172 }
173 
174 /* list watchpoints */
175 /*ARGSUSED*/
176 void
177 db_listwatch_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif)
178 {
179 	db_list_watchpoints();
180 }
181 
182 void
183 db_set_watchpoints(void)
184 {
185 	db_watchpoint_t	watch;
186 
187 	if (!db_watchpoints_inserted && db_watchpoint_list != NULL) {
188 		for (watch = db_watchpoint_list; watch != 0;
189 		    watch = watch->link)
190 			pmap_protect(pmap_kernel(), trunc_page(watch->loaddr),
191 			    round_page(watch->hiaddr), VM_PROT_READ);
192 		pmap_update(pmap_kernel());
193 		db_watchpoints_inserted = TRUE;
194 	}
195 }
196 
197 void
198 db_clear_watchpoints(void)
199 {
200 	db_watchpoints_inserted = FALSE;
201 }
202