db_watch.c revision 79573
1166551Smarcel/* 2166551Smarcel * Mach Operating System 3166551Smarcel * Copyright (c) 1991,1990 Carnegie Mellon University 4166551Smarcel * All Rights Reserved. 5166551Smarcel * 6166551Smarcel * Permission to use, copy, modify and distribute this software and its 7166551Smarcel * documentation is hereby granted, provided that both the copyright 8166551Smarcel * notice and this permission notice appear in all copies of the 9166551Smarcel * software, derivative works or modified versions, and any portions 10166551Smarcel * thereof, and that both notices appear in supporting documentation. 11166551Smarcel * 12166551Smarcel * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS 13166551Smarcel * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR 14166551Smarcel * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 15166551Smarcel * 16166551Smarcel * Carnegie Mellon requests users of this software to return to 17166551Smarcel * 18166551Smarcel * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 19166551Smarcel * School of Computer Science 20166551Smarcel * Carnegie Mellon University 21166551Smarcel * Pittsburgh PA 15213-3890 22166551Smarcel * 23166551Smarcel * any improvements or extensions that they make and grant Carnegie the 24166551Smarcel * rights to redistribute these changes. 25166551Smarcel * 26166551Smarcel * $FreeBSD: head/sys/ddb/db_watch.c 79573 2001-07-11 03:15:25Z bsd $ 27166551Smarcel */ 28166551Smarcel 29166551Smarcel/* 30166551Smarcel * Author: Richard P. Draves, Carnegie Mellon University 31166551Smarcel * Date: 10/90 32166551Smarcel */ 33166551Smarcel 34166551Smarcel#include <sys/param.h> 35166551Smarcel#include <sys/kernel.h> 36166551Smarcel#include <sys/lock.h> 37166551Smarcel#include <sys/proc.h> 38166551Smarcel 39166551Smarcel#include <vm/vm.h> 40179747Smarcel#include <vm/pmap.h> 41179747Smarcel#include <vm/vm_map.h> 42179747Smarcel 43166551Smarcel#include <ddb/ddb.h> 44166551Smarcel#include <ddb/db_watch.h> 45166551Smarcel 46166551Smarcel/* 47166551Smarcel * Watchpoints. 48166551Smarcel */ 49166551Smarcel 50166551Smarcelstatic boolean_t db_watchpoints_inserted = TRUE; 51179747Smarcel 52179747Smarcel#define NWATCHPOINTS 100 53166551Smarcelstatic struct db_watchpoint db_watch_table[NWATCHPOINTS]; 54166551Smarcelstatic db_watchpoint_t db_next_free_watchpoint = &db_watch_table[0]; 55166551Smarcelstatic db_watchpoint_t db_free_watchpoints = 0; 56166551Smarcelstatic db_watchpoint_t db_watchpoint_list = 0; 57166551Smarcel 58166551Smarcelstatic db_watchpoint_t db_watchpoint_alloc __P((void)); 59166551Smarcelstatic void db_watchpoint_free __P((db_watchpoint_t watch)); 60166551Smarcelstatic void db_delete_watchpoint __P((vm_map_t map, 61166551Smarcel db_addr_t addr)); 62172855Smarcel#ifdef notused 63166551Smarcelstatic boolean_t db_find_watchpoint __P((vm_map_t map, db_addr_t addr, 64166551Smarcel db_regs_t *regs)); 65166551Smarcel#endif 66166551Smarcelstatic void db_list_watchpoints __P((void)); 67static void db_set_watchpoint __P((vm_map_t map, db_addr_t addr, 68 vm_size_t size)); 69 70int db_md_set_watchpoint __P((db_expr_t addr, db_expr_t size)); 71int db_md_clr_watchpoint __P((db_expr_t addr, db_expr_t size)); 72void db_md_list_watchpoints __P((void)); 73 74 75db_watchpoint_t 76db_watchpoint_alloc() 77{ 78 register db_watchpoint_t watch; 79 80 if ((watch = db_free_watchpoints) != 0) { 81 db_free_watchpoints = watch->link; 82 return (watch); 83 } 84 if (db_next_free_watchpoint == &db_watch_table[NWATCHPOINTS]) { 85 db_printf("All watchpoints used.\n"); 86 return (0); 87 } 88 watch = db_next_free_watchpoint; 89 db_next_free_watchpoint++; 90 91 return (watch); 92} 93 94void 95db_watchpoint_free(watch) 96 register db_watchpoint_t watch; 97{ 98 watch->link = db_free_watchpoints; 99 db_free_watchpoints = watch; 100} 101 102static void 103db_set_watchpoint(map, addr, size) 104 vm_map_t map; 105 db_addr_t addr; 106 vm_size_t size; 107{ 108 register db_watchpoint_t watch; 109 110 if (map == NULL) { 111 db_printf("No map.\n"); 112 return; 113 } 114 115 /* 116 * Should we do anything fancy with overlapping regions? 117 */ 118 119 for (watch = db_watchpoint_list; 120 watch != 0; 121 watch = watch->link) 122 if (db_map_equal(watch->map, map) && 123 (watch->loaddr == addr) && 124 (watch->hiaddr == addr+size)) { 125 db_printf("Already set.\n"); 126 return; 127 } 128 129 watch = db_watchpoint_alloc(); 130 if (watch == 0) { 131 db_printf("Too many watchpoints.\n"); 132 return; 133 } 134 135 watch->map = map; 136 watch->loaddr = addr; 137 watch->hiaddr = addr+size; 138 139 watch->link = db_watchpoint_list; 140 db_watchpoint_list = watch; 141 142 db_watchpoints_inserted = FALSE; 143} 144 145static void 146db_delete_watchpoint(map, addr) 147 vm_map_t map; 148 db_addr_t addr; 149{ 150 register db_watchpoint_t watch; 151 register db_watchpoint_t *prev; 152 153 for (prev = &db_watchpoint_list; 154 (watch = *prev) != 0; 155 prev = &watch->link) 156 if (db_map_equal(watch->map, map) && 157 (watch->loaddr <= addr) && 158 (addr < watch->hiaddr)) { 159 *prev = watch->link; 160 db_watchpoint_free(watch); 161 return; 162 } 163 164 db_printf("Not set.\n"); 165} 166 167static void 168db_list_watchpoints() 169{ 170 register db_watchpoint_t watch; 171 172 if (db_watchpoint_list == 0) { 173 db_printf("No watchpoints set\n"); 174 return; 175 } 176 177 db_printf(" Map Address Size\n"); 178 for (watch = db_watchpoint_list; 179 watch != 0; 180 watch = watch->link) 181 db_printf("%s%8p %8lx %lx\n", 182 db_map_current(watch->map) ? "*" : " ", 183 (void *)watch->map, (long)watch->loaddr, 184 (long)watch->hiaddr - (long)watch->loaddr); 185} 186 187/* Delete watchpoint */ 188/*ARGSUSED*/ 189void 190db_deletewatch_cmd(addr, have_addr, count, modif) 191 db_expr_t addr; 192 boolean_t have_addr; 193 db_expr_t count; 194 char * modif; 195{ 196 db_delete_watchpoint(db_map_addr(addr), addr); 197} 198 199/* Set watchpoint */ 200/*ARGSUSED*/ 201void 202db_watchpoint_cmd(addr, have_addr, count, modif) 203 db_expr_t addr; 204 boolean_t have_addr; 205 db_expr_t count; 206 char * modif; 207{ 208 vm_size_t size; 209 db_expr_t value; 210 211 if (db_expression(&value)) 212 size = (vm_size_t) value; 213 else 214 size = 4; 215 db_skip_to_eol(); 216 217 db_set_watchpoint(db_map_addr(addr), addr, size); 218} 219 220/* 221 * At least one non-optional show-command must be implemented using 222 * DB_SHOW_COMMAND() so that db_show_cmd_set gets created. Here is one. 223 */ 224DB_SHOW_COMMAND(watches, db_listwatch_cmd) 225{ 226 db_list_watchpoints(); 227 db_md_list_watchpoints(); 228} 229 230void 231db_set_watchpoints() 232{ 233 register db_watchpoint_t watch; 234 235 if (!db_watchpoints_inserted) { 236 for (watch = db_watchpoint_list; 237 watch != 0; 238 watch = watch->link) 239 pmap_protect(watch->map->pmap, 240 trunc_page(watch->loaddr), 241 round_page(watch->hiaddr), 242 VM_PROT_READ); 243 244 db_watchpoints_inserted = TRUE; 245 } 246} 247 248void 249db_clear_watchpoints() 250{ 251 db_watchpoints_inserted = FALSE; 252} 253 254#ifdef notused 255static boolean_t 256db_find_watchpoint(map, addr, regs) 257 vm_map_t map; 258 db_addr_t addr; 259 db_regs_t *regs; 260{ 261 register db_watchpoint_t watch; 262 db_watchpoint_t found = 0; 263 264 for (watch = db_watchpoint_list; 265 watch != 0; 266 watch = watch->link) 267 if (db_map_equal(watch->map, map)) { 268 if ((watch->loaddr <= addr) && 269 (addr < watch->hiaddr)) 270 return (TRUE); 271 else if ((trunc_page(watch->loaddr) <= addr) && 272 (addr < round_page(watch->hiaddr))) 273 found = watch; 274 } 275 276 /* 277 * We didn't hit exactly on a watchpoint, but we are 278 * in a protected region. We want to single-step 279 * and then re-protect. 280 */ 281 282 if (found) { 283 db_watchpoints_inserted = FALSE; 284 db_single_step(regs); 285 } 286 287 return (FALSE); 288} 289#endif 290 291 292 293/* Delete hardware watchpoint */ 294/*ARGSUSED*/ 295void 296db_deletehwatch_cmd(addr, have_addr, count, modif) 297 db_expr_t addr; 298 boolean_t have_addr; 299 db_expr_t count; 300 char * modif; 301{ 302 int rc; 303 304 if (count < 0) 305 count = 4; 306 307 rc = db_md_clr_watchpoint(addr, count); 308 if (rc < 0) 309 db_printf("hardware watchpoint could not be deleted\n"); 310} 311 312/* Set hardware watchpoint */ 313/*ARGSUSED*/ 314void 315db_hwatchpoint_cmd(addr, have_addr, count, modif) 316 db_expr_t addr; 317 boolean_t have_addr; 318 db_expr_t count; 319 char * modif; 320{ 321 int rc; 322 323 if (count < 0) 324 count = 4; 325 326 rc = db_md_set_watchpoint(addr, count); 327 if (rc < 0) 328 db_printf("hardware watchpoint could not be set\n"); 329} 330