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