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