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