1 /* $OpenBSD: db_watch.c,v 1.19 2023/03/08 04:43:07 guenther 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
db_watchpoint_alloc(void)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
db_watchpoint_free(db_watchpoint_t watch)79 db_watchpoint_free(db_watchpoint_t watch)
80 {
81 watch->link = db_free_watchpoints;
82 db_free_watchpoints = watch;
83 }
84
85 void
db_set_watchpoint(vaddr_t addr,vsize_t size)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
db_delete_watchpoint(vaddr_t addr)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
db_list_watchpoints(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 void
db_deletewatch_cmd(db_expr_t addr,int have_addr,db_expr_t count,char * modif)150 db_deletewatch_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif)
151 {
152 db_delete_watchpoint(addr);
153 }
154
155 /* Set watchpoint */
156 void
db_watchpoint_cmd(db_expr_t addr,int have_addr,db_expr_t count,char * modif)157 db_watchpoint_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif)
158 {
159 vsize_t size;
160 db_expr_t value;
161
162 if (db_expression(&value))
163 size = (vsize_t) value;
164 else
165 size = 4;
166 db_skip_to_eol();
167
168 db_set_watchpoint(addr, size);
169 }
170
171 /* list watchpoints */
172 void
db_listwatch_cmd(db_expr_t addr,int have_addr,db_expr_t count,char * modif)173 db_listwatch_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif)
174 {
175 db_list_watchpoints();
176 }
177
178 void
db_set_watchpoints(void)179 db_set_watchpoints(void)
180 {
181 db_watchpoint_t watch;
182
183 if (!db_watchpoints_inserted && db_watchpoint_list != NULL) {
184 for (watch = db_watchpoint_list; watch != 0;
185 watch = watch->link)
186 pmap_protect(pmap_kernel(), trunc_page(watch->loaddr),
187 round_page(watch->hiaddr), PROT_READ);
188 pmap_update(pmap_kernel());
189 db_watchpoints_inserted = 1;
190 }
191 }
192
193 void
db_clear_watchpoints(void)194 db_clear_watchpoints(void)
195 {
196 db_watchpoints_inserted = 0;
197 }
198