db_watch.c revision 1.11
1/*	$OpenBSD: db_watch.c,v 1.11 2014/07/08 13:02:57 deraadt 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#include <sys/proc.h>
36
37#include <machine/db_machdep.h>
38
39#include <ddb/db_break.h>
40#include <ddb/db_watch.h>
41#include <ddb/db_lex.h>
42#include <ddb/db_access.h>
43#include <ddb/db_run.h>
44#include <ddb/db_sym.h>
45#include <ddb/db_output.h>
46#include <ddb/db_command.h>
47#include <ddb/db_extern.h>
48
49/*
50 * Watchpoints.
51 */
52
53boolean_t	db_watchpoints_inserted = TRUE;
54
55#define	NWATCHPOINTS	100
56struct db_watchpoint	db_watch_table[NWATCHPOINTS];
57db_watchpoint_t		db_next_free_watchpoint = &db_watch_table[0];
58db_watchpoint_t		db_free_watchpoints = 0;
59db_watchpoint_t		db_watchpoint_list = 0;
60
61db_watchpoint_t
62db_watchpoint_alloc(void)
63{
64	db_watchpoint_t	watch;
65
66	if ((watch = db_free_watchpoints) != 0) {
67	    db_free_watchpoints = watch->link;
68	    return (watch);
69	}
70	if (db_next_free_watchpoint == &db_watch_table[NWATCHPOINTS]) {
71	    db_printf("All watchpoints used.\n");
72	    return (0);
73	}
74	watch = db_next_free_watchpoint;
75	db_next_free_watchpoint++;
76
77	return (watch);
78}
79
80void
81db_watchpoint_free(db_watchpoint_t watch)
82{
83	watch->link = db_free_watchpoints;
84	db_free_watchpoints = watch;
85}
86
87void
88db_set_watchpoint(db_addr_t addr, vsize_t size)
89{
90	db_watchpoint_t	watch;
91
92	/*
93	 *	Should we do anything fancy with overlapping regions?
94	 */
95
96	for (watch = db_watchpoint_list; watch != 0; watch = watch->link)
97		if (watch->loaddr == addr && watch->hiaddr == addr + size) {
98			db_printf("Already set.\n");
99			return;
100		}
101
102	watch = db_watchpoint_alloc();
103	if (watch == 0) {
104		db_printf("Too many watchpoints.\n");
105		return;
106	}
107
108	watch->loaddr = addr;
109	watch->hiaddr = addr+size;
110
111	watch->link = db_watchpoint_list;
112	db_watchpoint_list = watch;
113
114	db_watchpoints_inserted = FALSE;
115}
116
117void
118db_delete_watchpoint(db_addr_t addr)
119{
120	db_watchpoint_t	watch;
121	db_watchpoint_t	*prev;
122
123	for (prev = &db_watchpoint_list; (watch = *prev) != 0;
124	   prev = &watch->link)
125		if (watch->loaddr <= addr && addr < watch->hiaddr) {
126			*prev = watch->link;
127			db_watchpoint_free(watch);
128			return;
129		}
130
131	db_printf("Not set.\n");
132}
133
134void
135db_list_watchpoints(void)
136{
137	db_watchpoint_t	watch;
138
139	if (db_watchpoint_list == 0) {
140	    db_printf("No watchpoints set\n");
141	    return;
142	}
143
144	db_printf("  Address  Size\n");
145	for (watch = db_watchpoint_list; watch != 0; watch = watch->link)
146		db_printf("%8lx  %lx\n",
147		    watch->loaddr, watch->hiaddr - watch->loaddr);
148}
149
150/* Delete watchpoint */
151/*ARGSUSED*/
152void
153db_deletewatch_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif)
154{
155	db_delete_watchpoint(addr);
156}
157
158/* Set watchpoint */
159/*ARGSUSED*/
160void
161db_watchpoint_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif)
162{
163	vsize_t 	size;
164	db_expr_t	value;
165
166	if (db_expression(&value))
167	    size = (vsize_t) value;
168	else
169	    size = 4;
170	db_skip_to_eol();
171
172	db_set_watchpoint(addr, size);
173}
174
175/* list watchpoints */
176/*ARGSUSED*/
177void
178db_listwatch_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif)
179{
180	db_list_watchpoints();
181}
182
183void
184db_set_watchpoints(void)
185{
186	db_watchpoint_t	watch;
187
188	if (!db_watchpoints_inserted && db_watchpoint_list != NULL) {
189		for (watch = db_watchpoint_list; watch != 0;
190		    watch = watch->link)
191			pmap_protect(pmap_kernel(), trunc_page(watch->loaddr),
192			    round_page(watch->hiaddr), VM_PROT_READ);
193		pmap_update(pmap_kernel());
194		db_watchpoints_inserted = TRUE;
195	}
196}
197
198void
199db_clear_watchpoints(void)
200{
201	db_watchpoints_inserted = FALSE;
202}
203