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
51int db_watchpoints_inserted = 1;
52
53#define	NWATCHPOINTS	100
54struct db_watchpoint	db_watch_table[NWATCHPOINTS];
55db_watchpoint_t		db_next_free_watchpoint = &db_watch_table[0];
56db_watchpoint_t		db_free_watchpoints = 0;
57db_watchpoint_t		db_watchpoint_list = 0;
58
59db_watchpoint_t
60db_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
78void
79db_watchpoint_free(db_watchpoint_t watch)
80{
81	watch->link = db_free_watchpoints;
82	db_free_watchpoints = watch;
83}
84
85void
86db_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
115void
116db_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
132void
133db_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 */
149void
150db_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 */
156void
157db_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 */
172void
173db_listwatch_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif)
174{
175	db_list_watchpoints();
176}
177
178void
179db_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
193void
194db_clear_watchpoints(void)
195{
196	db_watchpoints_inserted = 0;
197}
198