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 /* 27 * $Id: db_watch.c,v 1.2 1993/05/20 03:39:38 cgd Exp $ 28 * 29 * HISTORY 30 * $Log: db_watch.c,v $ 31 * Revision 1.2 1993/05/20 03:39:38 cgd 32 * add explicit rcs id 33 * 34 * Revision 1.1.1.1 1993/03/21 09:46:27 cgd 35 * initial import of 386bsd-0.1 sources 36 * 37 * Revision 1.1 1992/03/25 21:45:37 pace 38 * Initial revision 39 * 40 * Revision 2.5 91/02/05 17:07:27 mrt 41 * Changed to new Mach copyright 42 * [91/01/31 16:20:02 mrt] 43 * 44 * Revision 2.4 91/01/08 15:09:24 rpd 45 * Use db_map_equal, db_map_current, db_map_addr. 46 * [90/11/10 rpd] 47 * 48 * Revision 2.3 90/11/05 14:26:39 rpd 49 * Initialize db_watchpoints_inserted to TRUE. 50 * [90/11/04 rpd] 51 * 52 * Revision 2.2 90/10/25 14:44:16 rwd 53 * Made db_watchpoint_cmd parse a size argument. 54 * [90/10/17 rpd] 55 * Generalized the watchpoint support. 56 * [90/10/16 rwd] 57 * Created. 58 * [90/10/16 rpd] 59 * 60 */ 61 /* 62 * Author: Richard P. Draves, Carnegie Mellon University 63 * Date: 10/90 64 */ 65 66 #include "param.h" 67 #include "proc.h" 68 #include <machine/db_machdep.h> 69 70 #include <vm/vm_map.h> 71 #include <ddb/db_lex.h> 72 #include <ddb/db_watch.h> 73 #include <ddb/db_access.h> 74 #include <ddb/db_sym.h> 75 #include <machine/db_machdep.h> 76 77 /* 78 * Watchpoints. 79 */ 80 81 extern boolean_t db_map_equal(); 82 extern boolean_t db_map_current(); 83 extern vm_map_t db_map_addr(); 84 85 boolean_t db_watchpoints_inserted = TRUE; 86 87 #define NWATCHPOINTS 100 88 struct db_watchpoint db_watch_table[NWATCHPOINTS]; 89 db_watchpoint_t db_next_free_watchpoint = &db_watch_table[0]; 90 db_watchpoint_t db_free_watchpoints = 0; 91 db_watchpoint_t db_watchpoint_list = 0; 92 93 db_watchpoint_t 94 db_watchpoint_alloc() 95 { 96 register db_watchpoint_t watch; 97 98 if ((watch = db_free_watchpoints) != 0) { 99 db_free_watchpoints = watch->link; 100 return (watch); 101 } 102 if (db_next_free_watchpoint == &db_watch_table[NWATCHPOINTS]) { 103 db_printf("All watchpoints used.\n"); 104 return (0); 105 } 106 watch = db_next_free_watchpoint; 107 db_next_free_watchpoint++; 108 109 return (watch); 110 } 111 112 void 113 db_watchpoint_free(watch) 114 register db_watchpoint_t watch; 115 { 116 watch->link = db_free_watchpoints; 117 db_free_watchpoints = watch; 118 } 119 120 void 121 db_set_watchpoint(map, addr, size) 122 vm_map_t map; 123 db_addr_t addr; 124 vm_size_t size; 125 { 126 register db_watchpoint_t watch; 127 128 if (map == NULL) { 129 db_printf("No map.\n"); 130 return; 131 } 132 133 /* 134 * Should we do anything fancy with overlapping regions? 135 */ 136 137 for (watch = db_watchpoint_list; 138 watch != 0; 139 watch = watch->link) 140 if (db_map_equal(watch->map, map) && 141 (watch->loaddr == addr) && 142 (watch->hiaddr == addr+size)) { 143 db_printf("Already set.\n"); 144 return; 145 } 146 147 watch = db_watchpoint_alloc(); 148 if (watch == 0) { 149 db_printf("Too many watchpoints.\n"); 150 return; 151 } 152 153 watch->map = map; 154 watch->loaddr = addr; 155 watch->hiaddr = addr+size; 156 157 watch->link = db_watchpoint_list; 158 db_watchpoint_list = watch; 159 160 db_watchpoints_inserted = FALSE; 161 } 162 163 void 164 db_delete_watchpoint(map, addr) 165 vm_map_t map; 166 db_addr_t addr; 167 { 168 register db_watchpoint_t watch; 169 register db_watchpoint_t *prev; 170 171 for (prev = &db_watchpoint_list; 172 (watch = *prev) != 0; 173 prev = &watch->link) 174 if (db_map_equal(watch->map, map) && 175 (watch->loaddr <= addr) && 176 (addr < watch->hiaddr)) { 177 *prev = watch->link; 178 db_watchpoint_free(watch); 179 return; 180 } 181 182 db_printf("Not set.\n"); 183 } 184 185 void 186 db_list_watchpoints() 187 { 188 register db_watchpoint_t watch; 189 190 if (db_watchpoint_list == 0) { 191 db_printf("No watchpoints set\n"); 192 return; 193 } 194 195 db_printf(" Map Address Size\n"); 196 for (watch = db_watchpoint_list; 197 watch != 0; 198 watch = watch->link) 199 db_printf("%s%8x %8x %x\n", 200 db_map_current(watch->map) ? "*" : " ", 201 watch->map, watch->loaddr, 202 watch->hiaddr - watch->loaddr); 203 } 204 205 /* Delete watchpoint */ 206 /*ARGSUSED*/ 207 void 208 db_deletewatch_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_delete_watchpoint(db_map_addr(addr), addr); 215 } 216 217 /* Set watchpoint */ 218 /*ARGSUSED*/ 219 void 220 db_watchpoint_cmd(addr, have_addr, count, modif) 221 db_expr_t addr; 222 int have_addr; 223 db_expr_t count; 224 char * modif; 225 { 226 vm_size_t size; 227 db_expr_t value; 228 229 if (db_expression(&value)) 230 size = (vm_size_t) value; 231 else 232 size = 4; 233 db_skip_to_eol(); 234 235 db_set_watchpoint(db_map_addr(addr), addr, size); 236 } 237 238 /* list watchpoints */ 239 void 240 db_listwatch_cmd() 241 { 242 db_list_watchpoints(); 243 } 244 245 void 246 db_set_watchpoints() 247 { 248 register db_watchpoint_t watch; 249 250 if (!db_watchpoints_inserted) { 251 for (watch = db_watchpoint_list; 252 watch != 0; 253 watch = watch->link) 254 pmap_protect(watch->map->pmap, 255 trunc_page(watch->loaddr), 256 round_page(watch->hiaddr), 257 VM_PROT_READ); 258 259 db_watchpoints_inserted = TRUE; 260 } 261 } 262 263 void 264 db_clear_watchpoints() 265 { 266 db_watchpoints_inserted = FALSE; 267 } 268 269 boolean_t 270 db_find_watchpoint(map, addr, regs) 271 vm_map_t map; 272 db_addr_t addr; 273 db_regs_t *regs; 274 { 275 register db_watchpoint_t watch; 276 db_watchpoint_t found = 0; 277 278 for (watch = db_watchpoint_list; 279 watch != 0; 280 watch = watch->link) 281 if (db_map_equal(watch->map, map)) { 282 if ((watch->loaddr <= addr) && 283 (addr < watch->hiaddr)) 284 return (TRUE); 285 else if ((trunc_page(watch->loaddr) <= addr) && 286 (addr < round_page(watch->hiaddr))) 287 found = watch; 288 } 289 290 /* 291 * We didn't hit exactly on a watchpoint, but we are 292 * in a protected region. We want to single-step 293 * and then re-protect. 294 */ 295 296 if (found) { 297 db_watchpoints_inserted = FALSE; 298 db_single_step(regs); 299 } 300 301 return (FALSE); 302 } 303