db_watch.c revision 1.16
1/*	$OpenBSD: db_watch.c,v 1.16 2016/04/19 10:24:42 mpi 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(db_addr_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(db_addr_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 */
149/*ARGSUSED*/
150void
151db_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*/
158void
159db_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*/
175void
176db_listwatch_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif)
177{
178	db_list_watchpoints();
179}
180
181void
182db_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
196void
197db_clear_watchpoints(void)
198{
199	db_watchpoints_inserted = 0;
200}
201