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.14 1997/02/22 09:28:33 peter Exp $ 27 */ 28 29 /* 30 * Author: Richard P. Draves, Carnegie Mellon University 31 * Date: 10/90 32 */ 33 34 #include <sys/param.h> 35 36 #include <vm/vm.h> 37 #include <sys/lock.h> 38 #include <vm/pmap.h> 39 #include <vm/vm_map.h> 40 #include <vm/vm_prot.h> 41 42 #include <ddb/ddb.h> 43 #include <ddb/db_watch.h> 44 45 /* 46 * Watchpoints. 47 */ 48 49 static boolean_t db_watchpoints_inserted = TRUE; 50 51 #define NWATCHPOINTS 100 52 static struct db_watchpoint db_watch_table[NWATCHPOINTS]; 53 static db_watchpoint_t db_next_free_watchpoint = &db_watch_table[0]; 54 static db_watchpoint_t db_free_watchpoints = 0; 55 static db_watchpoint_t db_watchpoint_list = 0; 56 57 static db_watchpoint_t db_watchpoint_alloc __P((void)); 58 static void db_watchpoint_free __P((db_watchpoint_t watch)); 59 static void db_delete_watchpoint __P((vm_map_t map, 60 db_addr_t addr)); 61 #ifdef notused 62 static boolean_t db_find_watchpoint __P((vm_map_t map, db_addr_t addr, 63 db_regs_t *regs)); 64 #endif 65 static void db_list_watchpoints __P((void)); 66 static void db_set_watchpoint __P((vm_map_t map, db_addr_t addr, 67 vm_size_t size)); 68 69 70 db_watchpoint_t 71 db_watchpoint_alloc() 72 { 73 register db_watchpoint_t watch; 74 75 if ((watch = db_free_watchpoints) != 0) { 76 db_free_watchpoints = watch->link; 77 return (watch); 78 } 79 if (db_next_free_watchpoint == &db_watch_table[NWATCHPOINTS]) { 80 db_printf("All watchpoints used.\n"); 81 return (0); 82 } 83 watch = db_next_free_watchpoint; 84 db_next_free_watchpoint++; 85 86 return (watch); 87 } 88 89 void 90 db_watchpoint_free(watch) 91 register db_watchpoint_t watch; 92 { 93 watch->link = db_free_watchpoints; 94 db_free_watchpoints = watch; 95 } 96 97 static void 98 db_set_watchpoint(map, addr, size) 99 vm_map_t map; 100 db_addr_t addr; 101 vm_size_t size; 102 { 103 register db_watchpoint_t watch; 104 105 if (map == NULL) { 106 db_printf("No map.\n"); 107 return; 108 } 109 110 /* 111 * Should we do anything fancy with overlapping regions? 112 */ 113 114 for (watch = db_watchpoint_list; 115 watch != 0; 116 watch = watch->link) 117 if (db_map_equal(watch->map, map) && 118 (watch->loaddr == addr) && 119 (watch->hiaddr == addr+size)) { 120 db_printf("Already set.\n"); 121 return; 122 } 123 124 watch = db_watchpoint_alloc(); 125 if (watch == 0) { 126 db_printf("Too many watchpoints.\n"); 127 return; 128 } 129 130 watch->map = map; 131 watch->loaddr = addr; 132 watch->hiaddr = addr+size; 133 134 watch->link = db_watchpoint_list; 135 db_watchpoint_list = watch; 136 137 db_watchpoints_inserted = FALSE; 138 } 139 140 static void 141 db_delete_watchpoint(map, addr) 142 vm_map_t map; 143 db_addr_t addr; 144 { 145 register db_watchpoint_t watch; 146 register db_watchpoint_t *prev; 147 148 for (prev = &db_watchpoint_list; 149 (watch = *prev) != 0; 150 prev = &watch->link) 151 if (db_map_equal(watch->map, map) && 152 (watch->loaddr <= addr) && 153 (addr < watch->hiaddr)) { 154 *prev = watch->link; 155 db_watchpoint_free(watch); 156 return; 157 } 158 159 db_printf("Not set.\n"); 160 } 161 162 static void 163 db_list_watchpoints() 164 { 165 register db_watchpoint_t watch; 166 167 if (db_watchpoint_list == 0) { 168 db_printf("No watchpoints set\n"); 169 return; 170 } 171 172 db_printf(" Map Address Size\n"); 173 for (watch = db_watchpoint_list; 174 watch != 0; 175 watch = watch->link) 176 db_printf("%s%8x %8x %x\n", 177 db_map_current(watch->map) ? "*" : " ", 178 watch->map, watch->loaddr, 179 watch->hiaddr - watch->loaddr); 180 } 181 182 /* Delete watchpoint */ 183 /*ARGSUSED*/ 184 void 185 db_deletewatch_cmd(addr, have_addr, count, modif) 186 db_expr_t addr; 187 boolean_t have_addr; 188 db_expr_t count; 189 char * modif; 190 { 191 db_delete_watchpoint(db_map_addr(addr), addr); 192 } 193 194 /* Set watchpoint */ 195 /*ARGSUSED*/ 196 void 197 db_watchpoint_cmd(addr, have_addr, count, modif) 198 db_expr_t addr; 199 boolean_t have_addr; 200 db_expr_t count; 201 char * modif; 202 { 203 vm_size_t size; 204 db_expr_t value; 205 206 if (db_expression(&value)) 207 size = (vm_size_t) value; 208 else 209 size = 4; 210 db_skip_to_eol(); 211 212 db_set_watchpoint(db_map_addr(addr), addr, size); 213 } 214 215 /* list watchpoints */ 216 void 217 db_listwatch_cmd(dummy1, dummy2, dummy3, dummy4) 218 db_expr_t dummy1; 219 boolean_t dummy2; 220 db_expr_t dummy3; 221 char * dummy4; 222 { 223 db_list_watchpoints(); 224 } 225 226 void 227 db_set_watchpoints() 228 { 229 register db_watchpoint_t watch; 230 231 if (!db_watchpoints_inserted) { 232 for (watch = db_watchpoint_list; 233 watch != 0; 234 watch = watch->link) 235 pmap_protect(watch->map->pmap, 236 trunc_page(watch->loaddr), 237 round_page(watch->hiaddr), 238 VM_PROT_READ); 239 240 db_watchpoints_inserted = TRUE; 241 } 242 } 243 244 void 245 db_clear_watchpoints() 246 { 247 db_watchpoints_inserted = FALSE; 248 } 249 250 #ifdef notused 251 static boolean_t 252 db_find_watchpoint(map, addr, regs) 253 vm_map_t map; 254 db_addr_t addr; 255 db_regs_t *regs; 256 { 257 register db_watchpoint_t watch; 258 db_watchpoint_t found = 0; 259 260 for (watch = db_watchpoint_list; 261 watch != 0; 262 watch = watch->link) 263 if (db_map_equal(watch->map, map)) { 264 if ((watch->loaddr <= addr) && 265 (addr < watch->hiaddr)) 266 return (TRUE); 267 else if ((trunc_page(watch->loaddr) <= addr) && 268 (addr < round_page(watch->hiaddr))) 269 found = watch; 270 } 271 272 /* 273 * We didn't hit exactly on a watchpoint, but we are 274 * in a protected region. We want to single-step 275 * and then re-protect. 276 */ 277 278 if (found) { 279 db_watchpoints_inserted = FALSE; 280 db_single_step(regs); 281 } 282 283 return (FALSE); 284 } 285 #endif 286