db_watch.c revision 1.10
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
52boolean_t	db_watchpoints_inserted = TRUE;
53
54#define	NWATCHPOINTS	100
55struct db_watchpoint	db_watch_table[NWATCHPOINTS];
56db_watchpoint_t		db_next_free_watchpoint = &db_watch_table[0];
57db_watchpoint_t		db_free_watchpoints = 0;
58db_watchpoint_t		db_watchpoint_list = 0;
59
60db_watchpoint_t
61db_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
79void
80db_watchpoint_free(db_watchpoint_t watch)
81{
82	watch->link = db_free_watchpoints;
83	db_free_watchpoints = watch;
84}
85
86void
87db_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
116void
117db_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
133void
134db_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*/
151void
152db_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*/
159void
160db_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*/
176void
177db_listwatch_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif)
178{
179	db_list_watchpoints();
180}
181
182void
183db_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
197void
198db_clear_watchpoints(void)
199{
200	db_watchpoints_inserted = FALSE;
201}
202