Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/ddb/db_watch.c
39476 views
1
/*-
2
* SPDX-License-Identifier: MIT-CMU
3
*
4
* Mach Operating System
5
* Copyright (c) 1991,1990 Carnegie Mellon University
6
* All Rights Reserved.
7
*
8
* Permission to use, copy, modify and distribute this software and its
9
* documentation is hereby granted, provided that both the copyright
10
* notice and this permission notice appear in all copies of the
11
* software, derivative works or modified versions, and any portions
12
* thereof, and that both notices appear in supporting documentation.
13
*
14
* CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
15
* CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
16
* ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
17
*
18
* Carnegie Mellon requests users of this software to return to
19
*
20
* Software Distribution Coordinator or [email protected]
21
* School of Computer Science
22
* Carnegie Mellon University
23
* Pittsburgh PA 15213-3890
24
*
25
* any improvements or extensions that they make and grant Carnegie the
26
* rights to redistribute these changes.
27
*/
28
/*
29
* Author: Richard P. Draves, Carnegie Mellon University
30
* Date: 10/90
31
*/
32
33
#include <sys/param.h>
34
#include <sys/kdb.h>
35
#include <sys/kernel.h>
36
#include <sys/lock.h>
37
#include <sys/proc.h>
38
39
#include <vm/vm.h>
40
#include <vm/pmap.h>
41
#include <vm/vm_map.h>
42
43
#include <machine/kdb.h>
44
45
#include <ddb/ddb.h>
46
#include <ddb/db_watch.h>
47
48
/*
49
* Watchpoints.
50
*/
51
52
static bool db_watchpoints_inserted = true;
53
54
#define NWATCHPOINTS 100
55
static struct db_watchpoint db_watch_table[NWATCHPOINTS];
56
static db_watchpoint_t db_next_free_watchpoint = &db_watch_table[0];
57
static db_watchpoint_t db_free_watchpoints = 0;
58
static db_watchpoint_t db_watchpoint_list = 0;
59
60
static db_watchpoint_t db_watchpoint_alloc(void);
61
static void db_watchpoint_free(db_watchpoint_t watch);
62
static void db_delete_watchpoint(vm_map_t map, db_addr_t addr);
63
#ifdef notused
64
static bool db_find_watchpoint(vm_map_t map, db_addr_t addr,
65
db_regs_t *regs);
66
#endif
67
static void db_list_watchpoints(void);
68
static void db_set_watchpoint(vm_map_t map, db_addr_t addr,
69
vm_size_t size);
70
71
static db_watchpoint_t
72
db_watchpoint_alloc(void)
73
{
74
db_watchpoint_t watch;
75
76
if ((watch = db_free_watchpoints) != 0) {
77
db_free_watchpoints = watch->link;
78
return (watch);
79
}
80
if (db_next_free_watchpoint == &db_watch_table[NWATCHPOINTS]) {
81
db_printf("All watchpoints used.\n");
82
return (0);
83
}
84
watch = db_next_free_watchpoint;
85
db_next_free_watchpoint++;
86
87
return (watch);
88
}
89
90
static void
91
db_watchpoint_free(db_watchpoint_t watch)
92
{
93
watch->link = db_free_watchpoints;
94
db_free_watchpoints = watch;
95
}
96
97
static void
98
db_set_watchpoint(vm_map_t map, db_addr_t addr, vm_size_t size)
99
{
100
db_watchpoint_t watch;
101
102
if (map == NULL) {
103
db_printf("No map.\n");
104
return;
105
}
106
107
/*
108
* Should we do anything fancy with overlapping regions?
109
*/
110
111
for (watch = db_watchpoint_list;
112
watch != 0;
113
watch = watch->link)
114
if (db_map_equal(watch->map, map) &&
115
(watch->loaddr == addr) &&
116
(watch->hiaddr == addr+size)) {
117
db_printf("Already set.\n");
118
return;
119
}
120
121
watch = db_watchpoint_alloc();
122
if (watch == 0) {
123
db_printf("Too many watchpoints.\n");
124
return;
125
}
126
127
watch->map = map;
128
watch->loaddr = addr;
129
watch->hiaddr = addr+size;
130
131
watch->link = db_watchpoint_list;
132
db_watchpoint_list = watch;
133
134
db_watchpoints_inserted = false;
135
}
136
137
static void
138
db_delete_watchpoint(vm_map_t map, db_addr_t addr)
139
{
140
db_watchpoint_t watch;
141
db_watchpoint_t *prev;
142
143
for (prev = &db_watchpoint_list;
144
(watch = *prev) != 0;
145
prev = &watch->link)
146
if (db_map_equal(watch->map, map) &&
147
(watch->loaddr <= addr) &&
148
(addr < watch->hiaddr)) {
149
*prev = watch->link;
150
db_watchpoint_free(watch);
151
return;
152
}
153
154
db_printf("Not set.\n");
155
}
156
157
static void
158
db_list_watchpoints(void)
159
{
160
db_watchpoint_t watch;
161
162
if (db_watchpoint_list == 0) {
163
db_printf("No watchpoints set\n");
164
return;
165
}
166
167
#ifdef __LP64__
168
db_printf(" Map Address Size\n");
169
#else
170
db_printf(" Map Address Size\n");
171
#endif
172
for (watch = db_watchpoint_list;
173
watch != 0;
174
watch = watch->link)
175
#ifdef __LP64__
176
db_printf("%s%16p %16lx %lx\n",
177
#else
178
db_printf("%s%8p %8lx %lx\n",
179
#endif
180
db_map_current(watch->map) ? "*" : " ",
181
(void *)watch->map, (long)watch->loaddr,
182
(long)watch->hiaddr - (long)watch->loaddr);
183
}
184
185
/* Delete watchpoint */
186
/*ARGSUSED*/
187
void
188
db_deletewatch_cmd(db_expr_t addr, bool have_addr, db_expr_t count,
189
char *modif)
190
{
191
db_delete_watchpoint(db_map_addr(addr), addr);
192
}
193
194
/* Set watchpoint */
195
/*ARGSUSED*/
196
void
197
db_watchpoint_cmd(db_expr_t addr, bool have_addr, db_expr_t count,
198
char *modif)
199
{
200
vm_size_t size;
201
db_expr_t value;
202
203
if (db_expression(&value))
204
size = (vm_size_t) value;
205
else
206
size = 4;
207
db_skip_to_eol();
208
209
db_set_watchpoint(db_map_addr(addr), addr, size);
210
}
211
212
/*
213
* At least one non-optional show-command must be implemented using
214
* DB_SHOW_COMMAND() so that db_show_cmd_set gets created. Here is one.
215
*/
216
DB_SHOW_COMMAND_FLAGS(watches, db_listwatch_cmd, DB_CMD_MEMSAFE)
217
{
218
db_list_watchpoints();
219
db_md_list_watchpoints();
220
}
221
222
void
223
db_set_watchpoints(void)
224
{
225
db_watchpoint_t watch;
226
227
if (!db_watchpoints_inserted) {
228
for (watch = db_watchpoint_list;
229
watch != 0;
230
watch = watch->link)
231
pmap_protect(watch->map->pmap,
232
trunc_page(watch->loaddr),
233
round_page(watch->hiaddr),
234
VM_PROT_READ);
235
236
db_watchpoints_inserted = true;
237
}
238
}
239
240
void
241
db_clear_watchpoints(void)
242
{
243
db_watchpoints_inserted = false;
244
}
245
246
#ifdef notused
247
static bool
248
db_find_watchpoint(vm_map_t map, db_addr_t addr, db_regs_t regs)
249
{
250
db_watchpoint_t watch;
251
db_watchpoint_t found = 0;
252
253
for (watch = db_watchpoint_list;
254
watch != 0;
255
watch = watch->link)
256
if (db_map_equal(watch->map, map)) {
257
if ((watch->loaddr <= addr) &&
258
(addr < watch->hiaddr))
259
return (true);
260
else if ((trunc_page(watch->loaddr) <= addr) &&
261
(addr < round_page(watch->hiaddr)))
262
found = watch;
263
}
264
265
/*
266
* We didn't hit exactly on a watchpoint, but we are
267
* in a protected region. We want to single-step
268
* and then re-protect.
269
*/
270
271
if (found) {
272
db_watchpoints_inserted = false;
273
db_single_step(regs);
274
}
275
276
return (false);
277
}
278
#endif
279
280
/* Delete hardware watchpoint */
281
void
282
db_deletehwatch_cmd(db_expr_t addr, bool have_addr, db_expr_t size,
283
char *modif)
284
{
285
int rc;
286
287
if (size < 0)
288
size = 4;
289
290
rc = kdb_cpu_clr_watchpoint((vm_offset_t)addr, (vm_size_t)size);
291
switch (rc) {
292
case ENXIO:
293
/* Not supported, ignored. */
294
break;
295
case EINVAL:
296
db_printf("Invalid watchpoint address or size.\n");
297
break;
298
default:
299
if (rc != 0)
300
db_printf("Hardware watchpoint could not be deleted, "
301
"status=%d\n", rc);
302
break;
303
}
304
}
305
306
/* Set hardware watchpoint */
307
void
308
db_hwatchpoint_cmd(db_expr_t addr, bool have_addr, db_expr_t size,
309
char *modif)
310
{
311
int rc;
312
313
if (size < 0)
314
size = 4;
315
316
rc = kdb_cpu_set_watchpoint((vm_offset_t)addr, (vm_size_t)size,
317
KDB_DBG_ACCESS_W);
318
319
switch (rc) {
320
case EINVAL:
321
db_printf("Invalid watchpoint size or address.\n");
322
break;
323
case EBUSY:
324
db_printf("No hardware watchpoints available.\n");
325
break;
326
case ENXIO:
327
db_printf("Hardware watchpoints are not supported on this platform.\n");
328
break;
329
default:
330
if (rc != 0)
331
db_printf("Could not set hardware watchpoint, "
332
"status=%d\n", rc);
333
}
334
}
335
336