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 52 boolean_t db_watchpoints_inserted = TRUE; 53 54 #define NWATCHPOINTS 100 55 struct db_watchpoint db_watch_table[NWATCHPOINTS]; 56 db_watchpoint_t db_next_free_watchpoint = &db_watch_table[0]; 57 db_watchpoint_t db_free_watchpoints = 0; 58 db_watchpoint_t db_watchpoint_list = 0; 59 60 db_watchpoint_t 61 db_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 79 void 80 db_watchpoint_free(watch) 81 register db_watchpoint_t watch; 82 { 83 watch->link = db_free_watchpoints; 84 db_free_watchpoints = watch; 85 } 86 87 void 88 db_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 130 void 131 db_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 152 void 153 db_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*/ 174 void 175 db_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*/ 186 void 187 db_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*/ 207 void 208 db_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 217 void 218 db_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 235 void 236 db_clear_watchpoints() 237 { 238 db_watchpoints_inserted = FALSE; 239 } 240 241 boolean_t 242 db_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