db_watch.c revision 1.5
1/* $OpenBSD: db_watch.c,v 1.5 1999/09/11 00:44:59 mickey 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() 62{ 63 register 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(watch) 81 register db_watchpoint_t watch; 82{ 83 watch->link = db_free_watchpoints; 84 db_free_watchpoints = watch; 85} 86 87void 88db_set_watchpoint(map, addr, size) 89 vm_map_t map; 90 db_addr_t addr; 91 vsize_t size; 92{ 93 register db_watchpoint_t watch; 94 95 if (map == NULL) { 96 db_printf("No map.\n"); 97 return; 98 } 99 100 /* 101 * Should we do anything fancy with overlapping regions? 102 */ 103 104 for (watch = db_watchpoint_list; 105 watch != 0; 106 watch = watch->link) 107 if (db_map_equal(watch->map, map) && 108 (watch->loaddr == addr) && 109 (watch->hiaddr == addr+size)) { 110 db_printf("Already set.\n"); 111 return; 112 } 113 114 watch = db_watchpoint_alloc(); 115 if (watch == 0) { 116 db_printf("Too many watchpoints.\n"); 117 return; 118 } 119 120 watch->map = map; 121 watch->loaddr = addr; 122 watch->hiaddr = addr+size; 123 124 watch->link = db_watchpoint_list; 125 db_watchpoint_list = watch; 126 127 db_watchpoints_inserted = FALSE; 128} 129 130void 131db_delete_watchpoint(map, addr) 132 vm_map_t map; 133 db_addr_t addr; 134{ 135 register db_watchpoint_t watch; 136 register db_watchpoint_t *prev; 137 138 for (prev = &db_watchpoint_list; 139 (watch = *prev) != 0; 140 prev = &watch->link) 141 if (db_map_equal(watch->map, map) && 142 (watch->loaddr <= addr) && 143 (addr < watch->hiaddr)) { 144 *prev = watch->link; 145 db_watchpoint_free(watch); 146 return; 147 } 148 149 db_printf("Not set.\n"); 150} 151 152void 153db_list_watchpoints() 154{ 155 register db_watchpoint_t watch; 156 157 if (db_watchpoint_list == 0) { 158 db_printf("No watchpoints set\n"); 159 return; 160 } 161 162 db_printf(" Map Address Size\n"); 163 for (watch = db_watchpoint_list; 164 watch != 0; 165 watch = watch->link) 166 db_printf("%s%p %8lx %lx\n", 167 db_map_current(watch->map) ? "*" : " ", 168 watch->map, watch->loaddr, 169 watch->hiaddr - watch->loaddr); 170} 171 172/* Delete watchpoint */ 173/*ARGSUSED*/ 174void 175db_deletewatch_cmd(addr, have_addr, count, modif) 176 db_expr_t addr; 177 int have_addr; 178 db_expr_t count; 179 char * modif; 180{ 181 db_delete_watchpoint(db_map_addr(addr), addr); 182} 183 184/* Set watchpoint */ 185/*ARGSUSED*/ 186void 187db_watchpoint_cmd(addr, have_addr, count, modif) 188 db_expr_t addr; 189 int have_addr; 190 db_expr_t count; 191 char * modif; 192{ 193 vsize_t size; 194 db_expr_t value; 195 196 if (db_expression(&value)) 197 size = (vsize_t) value; 198 else 199 size = 4; 200 db_skip_to_eol(); 201 202 db_set_watchpoint(db_map_addr(addr), addr, size); 203} 204 205/* list watchpoints */ 206/*ARGSUSED*/ 207void 208db_listwatch_cmd(addr, have_addr, count, modif) 209 db_expr_t addr; 210 int have_addr; 211 db_expr_t count; 212 char * modif; 213{ 214 db_list_watchpoints(); 215} 216 217void 218db_set_watchpoints() 219{ 220 register db_watchpoint_t watch; 221 222 if (!db_watchpoints_inserted) { 223 for (watch = db_watchpoint_list; 224 watch != 0; 225 watch = watch->link) 226 pmap_protect(watch->map->pmap, 227 trunc_page(watch->loaddr), 228 round_page(watch->hiaddr), 229 VM_PROT_READ); 230 231 db_watchpoints_inserted = TRUE; 232 } 233} 234 235void 236db_clear_watchpoints() 237{ 238 db_watchpoints_inserted = FALSE; 239} 240 241boolean_t 242db_find_watchpoint(map, addr, regs) 243 vm_map_t map; 244 db_addr_t addr; 245 db_regs_t *regs; 246{ 247 register db_watchpoint_t watch; 248 db_watchpoint_t found = 0; 249 250 for (watch = db_watchpoint_list; 251 watch != 0; 252 watch = watch->link) 253 if (db_map_equal(watch->map, map)) { 254 if ((watch->loaddr <= addr) && 255 (addr < watch->hiaddr)) 256 return (TRUE); 257 else if ((trunc_page(watch->loaddr) <= addr) && 258 (addr < round_page(watch->hiaddr))) 259 found = watch; 260 } 261 262 /* 263 * We didn't hit exactly on a watchpoint, but we are 264 * in a protected region. We want to single-step 265 * and then re-protect. 266 */ 267 268 if (found) { 269 db_watchpoints_inserted = FALSE; 270 db_single_step(regs); 271 } 272 273 return (FALSE); 274} 275