1 /* $NetBSD: db_watch.c,v 1.7 1994/10/09 08:30:15 mycroft Exp $ */ 2 3 /* 4 * Mach Operating System 5 * Copyright (c) 1991,1990 Carnegie Mellon University 6 * All Rights Reserved. 7 * 8 * Permission to use, copy, modify and distribute this software and its 9 * documentation is hereby granted, provided that both the copyright 10 * notice and this permission notice appear in all copies of the 11 * software, derivative works or modified versions, and any portions 12 * thereof, and that both notices appear in supporting documentation. 13 * 14 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS 15 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR 16 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 17 * 18 * Carnegie Mellon requests users of this software to return to 19 * 20 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 21 * School of Computer Science 22 * Carnegie Mellon University 23 * Pittsburgh PA 15213-3890 24 * 25 * any improvements or extensions that they make and grant Carnegie the 26 * rights to redistribute these changes. 27 * 28 * Author: Richard P. Draves, Carnegie Mellon University 29 * Date: 10/90 30 */ 31 32 #include <sys/param.h> 33 #include <sys/proc.h> 34 35 #include <machine/db_machdep.h> 36 37 #include <ddb/db_break.h> 38 #include <ddb/db_watch.h> 39 #include <ddb/db_lex.h> 40 #include <ddb/db_access.h> 41 #include <ddb/db_sym.h> 42 43 /* 44 * Watchpoints. 45 */ 46 47 boolean_t db_watchpoints_inserted = TRUE; 48 49 #define NWATCHPOINTS 100 50 struct db_watchpoint db_watch_table[NWATCHPOINTS]; 51 db_watchpoint_t db_next_free_watchpoint = &db_watch_table[0]; 52 db_watchpoint_t db_free_watchpoints = 0; 53 db_watchpoint_t db_watchpoint_list = 0; 54 55 db_watchpoint_t 56 db_watchpoint_alloc() 57 { 58 register db_watchpoint_t watch; 59 60 if ((watch = db_free_watchpoints) != 0) { 61 db_free_watchpoints = watch->link; 62 return (watch); 63 } 64 if (db_next_free_watchpoint == &db_watch_table[NWATCHPOINTS]) { 65 db_printf("All watchpoints used.\n"); 66 return (0); 67 } 68 watch = db_next_free_watchpoint; 69 db_next_free_watchpoint++; 70 71 return (watch); 72 } 73 74 void 75 db_watchpoint_free(watch) 76 register db_watchpoint_t watch; 77 { 78 watch->link = db_free_watchpoints; 79 db_free_watchpoints = watch; 80 } 81 82 void 83 db_set_watchpoint(map, addr, size) 84 vm_map_t map; 85 db_addr_t addr; 86 vm_size_t size; 87 { 88 register db_watchpoint_t watch; 89 90 if (map == NULL) { 91 db_printf("No map.\n"); 92 return; 93 } 94 95 /* 96 * Should we do anything fancy with overlapping regions? 97 */ 98 99 for (watch = db_watchpoint_list; 100 watch != 0; 101 watch = watch->link) 102 if (db_map_equal(watch->map, map) && 103 (watch->loaddr == addr) && 104 (watch->hiaddr == addr+size)) { 105 db_printf("Already set.\n"); 106 return; 107 } 108 109 watch = db_watchpoint_alloc(); 110 if (watch == 0) { 111 db_printf("Too many watchpoints.\n"); 112 return; 113 } 114 115 watch->map = map; 116 watch->loaddr = addr; 117 watch->hiaddr = addr+size; 118 119 watch->link = db_watchpoint_list; 120 db_watchpoint_list = watch; 121 122 db_watchpoints_inserted = FALSE; 123 } 124 125 void 126 db_delete_watchpoint(map, addr) 127 vm_map_t map; 128 db_addr_t addr; 129 { 130 register db_watchpoint_t watch; 131 register db_watchpoint_t *prev; 132 133 for (prev = &db_watchpoint_list; 134 (watch = *prev) != 0; 135 prev = &watch->link) 136 if (db_map_equal(watch->map, map) && 137 (watch->loaddr <= addr) && 138 (addr < watch->hiaddr)) { 139 *prev = watch->link; 140 db_watchpoint_free(watch); 141 return; 142 } 143 144 db_printf("Not set.\n"); 145 } 146 147 void 148 db_list_watchpoints() 149 { 150 register db_watchpoint_t watch; 151 152 if (db_watchpoint_list == 0) { 153 db_printf("No watchpoints set\n"); 154 return; 155 } 156 157 db_printf(" Map Address Size\n"); 158 for (watch = db_watchpoint_list; 159 watch != 0; 160 watch = watch->link) 161 db_printf("%s%8x %8x %x\n", 162 db_map_current(watch->map) ? "*" : " ", 163 watch->map, watch->loaddr, 164 watch->hiaddr - watch->loaddr); 165 } 166 167 /* Delete watchpoint */ 168 /*ARGSUSED*/ 169 void 170 db_deletewatch_cmd(addr, have_addr, count, modif) 171 db_expr_t addr; 172 int have_addr; 173 db_expr_t count; 174 char * modif; 175 { 176 db_delete_watchpoint(db_map_addr(addr), addr); 177 } 178 179 /* Set watchpoint */ 180 /*ARGSUSED*/ 181 void 182 db_watchpoint_cmd(addr, have_addr, count, modif) 183 db_expr_t addr; 184 int have_addr; 185 db_expr_t count; 186 char * modif; 187 { 188 vm_size_t size; 189 db_expr_t value; 190 191 if (db_expression(&value)) 192 size = (vm_size_t) value; 193 else 194 size = 4; 195 db_skip_to_eol(); 196 197 db_set_watchpoint(db_map_addr(addr), addr, size); 198 } 199 200 /* list watchpoints */ 201 void 202 db_listwatch_cmd() 203 { 204 db_list_watchpoints(); 205 } 206 207 void 208 db_set_watchpoints() 209 { 210 register db_watchpoint_t watch; 211 212 if (!db_watchpoints_inserted) { 213 for (watch = db_watchpoint_list; 214 watch != 0; 215 watch = watch->link) 216 pmap_protect(watch->map->pmap, 217 trunc_page(watch->loaddr), 218 round_page(watch->hiaddr), 219 VM_PROT_READ); 220 221 db_watchpoints_inserted = TRUE; 222 } 223 } 224 225 void 226 db_clear_watchpoints() 227 { 228 db_watchpoints_inserted = FALSE; 229 } 230 231 boolean_t 232 db_find_watchpoint(map, addr, regs) 233 vm_map_t map; 234 db_addr_t addr; 235 db_regs_t *regs; 236 { 237 register db_watchpoint_t watch; 238 db_watchpoint_t found = 0; 239 240 for (watch = db_watchpoint_list; 241 watch != 0; 242 watch = watch->link) 243 if (db_map_equal(watch->map, map)) { 244 if ((watch->loaddr <= addr) && 245 (addr < watch->hiaddr)) 246 return (TRUE); 247 else if ((trunc_page(watch->loaddr) <= addr) && 248 (addr < round_page(watch->hiaddr))) 249 found = watch; 250 } 251 252 /* 253 * We didn't hit exactly on a watchpoint, but we are 254 * in a protected region. We want to single-step 255 * and then re-protect. 256 */ 257 258 if (found) { 259 db_watchpoints_inserted = FALSE; 260 db_single_step(regs); 261 } 262 263 return (FALSE); 264 } 265