xref: /openbsd/sys/ddb/db_watch.c (revision dda28197)
1 /*	$OpenBSD: db_watch.c,v 1.18 2020/10/15 03:14:00 deraadt 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/systm.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_run.h>
42 #include <ddb/db_sym.h>
43 #include <ddb/db_output.h>
44 #include <ddb/db_command.h>
45 #include <ddb/db_extern.h>
46 
47 /*
48  * Watchpoints.
49  */
50 
51 int db_watchpoints_inserted = 1;
52 
53 #define	NWATCHPOINTS	100
54 struct db_watchpoint	db_watch_table[NWATCHPOINTS];
55 db_watchpoint_t		db_next_free_watchpoint = &db_watch_table[0];
56 db_watchpoint_t		db_free_watchpoints = 0;
57 db_watchpoint_t		db_watchpoint_list = 0;
58 
59 db_watchpoint_t
60 db_watchpoint_alloc(void)
61 {
62 	db_watchpoint_t	watch;
63 
64 	if ((watch = db_free_watchpoints) != 0) {
65 		db_free_watchpoints = watch->link;
66 		return (watch);
67 	}
68 	if (db_next_free_watchpoint == &db_watch_table[NWATCHPOINTS]) {
69 		db_printf("All watchpoints used.\n");
70 		return (0);
71 	}
72 	watch = db_next_free_watchpoint;
73 	db_next_free_watchpoint++;
74 
75 	return (watch);
76 }
77 
78 void
79 db_watchpoint_free(db_watchpoint_t watch)
80 {
81 	watch->link = db_free_watchpoints;
82 	db_free_watchpoints = watch;
83 }
84 
85 void
86 db_set_watchpoint(vaddr_t addr, vsize_t size)
87 {
88 	db_watchpoint_t	watch;
89 
90 	/*
91 	 *	Should we do anything fancy with overlapping regions?
92 	 */
93 
94 	for (watch = db_watchpoint_list; watch != 0; watch = watch->link)
95 		if (watch->loaddr == addr && watch->hiaddr == addr + size) {
96 			db_printf("Already set.\n");
97 			return;
98 		}
99 
100 	watch = db_watchpoint_alloc();
101 	if (watch == 0) {
102 		db_printf("Too many watchpoints.\n");
103 		return;
104 	}
105 
106 	watch->loaddr = addr;
107 	watch->hiaddr = addr+size;
108 
109 	watch->link = db_watchpoint_list;
110 	db_watchpoint_list = watch;
111 
112 	db_watchpoints_inserted = 0;
113 }
114 
115 void
116 db_delete_watchpoint(vaddr_t addr)
117 {
118 	db_watchpoint_t	watch;
119 	db_watchpoint_t	*prev;
120 
121 	for (prev = &db_watchpoint_list; (watch = *prev) != 0;
122 	    prev = &watch->link)
123 		if (watch->loaddr <= addr && addr < watch->hiaddr) {
124 			*prev = watch->link;
125 			db_watchpoint_free(watch);
126 			return;
127 		}
128 
129 	db_printf("Not set.\n");
130 }
131 
132 void
133 db_list_watchpoints(void)
134 {
135 	db_watchpoint_t	watch;
136 
137 	if (db_watchpoint_list == 0) {
138 		db_printf("No watchpoints set\n");
139 		return;
140 	}
141 
142 	db_printf("  Address  Size\n");
143 	for (watch = db_watchpoint_list; watch != 0; watch = watch->link)
144 		db_printf("%8lx  %lx\n",
145 		    watch->loaddr, watch->hiaddr - watch->loaddr);
146 }
147 
148 /* Delete watchpoint */
149 /*ARGSUSED*/
150 void
151 db_deletewatch_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif)
152 {
153 	db_delete_watchpoint(addr);
154 }
155 
156 /* Set watchpoint */
157 /*ARGSUSED*/
158 void
159 db_watchpoint_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif)
160 {
161 	vsize_t		size;
162 	db_expr_t	value;
163 
164 	if (db_expression(&value))
165 		size = (vsize_t) value;
166 	else
167 		size = 4;
168 	db_skip_to_eol();
169 
170 	db_set_watchpoint(addr, size);
171 }
172 
173 /* list watchpoints */
174 /*ARGSUSED*/
175 void
176 db_listwatch_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif)
177 {
178 	db_list_watchpoints();
179 }
180 
181 void
182 db_set_watchpoints(void)
183 {
184 	db_watchpoint_t	watch;
185 
186 	if (!db_watchpoints_inserted && db_watchpoint_list != NULL) {
187 		for (watch = db_watchpoint_list; watch != 0;
188 		    watch = watch->link)
189 			pmap_protect(pmap_kernel(), trunc_page(watch->loaddr),
190 			    round_page(watch->hiaddr), PROT_READ);
191 		pmap_update(pmap_kernel());
192 		db_watchpoints_inserted = 1;
193 	}
194 }
195 
196 void
197 db_clear_watchpoints(void)
198 {
199 	db_watchpoints_inserted = 0;
200 }
201