1 /* $NetBSD: db_watch.c,v 1.27 2007/02/22 06:41:01 thorpej Exp $ */ 2 3 /* 4 * Mach Operating System 5 * Copyright (c) 1991,1990 Carnegie Mellon University 6 * All Rights Reserved. 7 * 8 * Permission to use, copy, modify and distribute this software and its 9 * documentation is hereby granted, provided that both the copyright 10 * notice and this permission notice appear in all copies of the 11 * software, derivative works or modified versions, and any portions 12 * thereof, and that both notices appear in supporting documentation. 13 * 14 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 15 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR 16 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 17 * 18 * Carnegie Mellon requests users of this software to return to 19 * 20 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 21 * School of Computer Science 22 * Carnegie Mellon University 23 * Pittsburgh PA 15213-3890 24 * 25 * any improvements or extensions that they make and grant Carnegie the 26 * rights to redistribute these changes. 27 * 28 * Author: Richard P. Draves, Carnegie Mellon University 29 * Date: 10/90 30 */ 31 32 #include <sys/cdefs.h> 33 __KERNEL_RCSID(0, "$NetBSD: db_watch.c,v 1.27 2007/02/22 06:41:01 thorpej Exp $"); 34 35 #include <sys/param.h> 36 #include <sys/proc.h> 37 38 #include <machine/db_machdep.h> 39 40 #include <ddb/db_break.h> 41 #include <ddb/db_watch.h> 42 #include <ddb/db_lex.h> 43 #include <ddb/db_access.h> 44 #include <ddb/db_run.h> 45 #include <ddb/db_sym.h> 46 #include <ddb/db_output.h> 47 #include <ddb/db_command.h> 48 #include <ddb/db_extern.h> 49 50 /* 51 * Watchpoints. 52 */ 53 54 static bool db_watchpoints_inserted = true; 55 56 #define NWATCHPOINTS 100 57 static struct db_watchpoint db_watch_table[NWATCHPOINTS]; 58 static db_watchpoint_t db_next_free_watchpoint = &db_watch_table[0]; 59 static db_watchpoint_t db_free_watchpoints = 0; 60 static db_watchpoint_t db_watchpoint_list = 0; 61 62 static void db_delete_watchpoint(struct vm_map *, db_addr_t); 63 static void db_list_watchpoints(void); 64 static void db_set_watchpoint(struct vm_map *, db_addr_t, vsize_t); 65 static db_watchpoint_t db_watchpoint_alloc(void); 66 static void db_watchpoint_free(db_watchpoint_t); 67 68 db_watchpoint_t 69 db_watchpoint_alloc(void) 70 { 71 db_watchpoint_t watch; 72 73 if ((watch = db_free_watchpoints) != 0) { 74 db_free_watchpoints = watch->link; 75 return (watch); 76 } 77 if (db_next_free_watchpoint == &db_watch_table[NWATCHPOINTS]) { 78 db_printf("All watchpoints used.\n"); 79 return (0); 80 } 81 watch = db_next_free_watchpoint; 82 db_next_free_watchpoint++; 83 84 return (watch); 85 } 86 87 void 88 db_watchpoint_free(db_watchpoint_t watch) 89 { 90 watch->link = db_free_watchpoints; 91 db_free_watchpoints = watch; 92 } 93 94 void 95 db_set_watchpoint(struct vm_map *map, db_addr_t addr, vsize_t size) 96 { 97 db_watchpoint_t watch; 98 99 if (map == NULL) { 100 db_printf("No map.\n"); 101 return; 102 } 103 104 /* 105 * Should we do anything fancy with overlapping regions? 106 */ 107 108 for (watch = db_watchpoint_list; watch != 0; watch = watch->link) 109 if (db_map_equal(watch->map, map) && 110 (watch->loaddr == addr) && 111 (watch->hiaddr == addr+size)) { 112 db_printf("Already set.\n"); 113 return; 114 } 115 116 watch = db_watchpoint_alloc(); 117 if (watch == 0) { 118 db_printf("Too many watchpoints.\n"); 119 return; 120 } 121 122 watch->map = map; 123 watch->loaddr = addr; 124 watch->hiaddr = addr+size; 125 126 watch->link = db_watchpoint_list; 127 db_watchpoint_list = watch; 128 129 db_watchpoints_inserted = false; 130 } 131 132 static void 133 db_delete_watchpoint(struct vm_map *map, db_addr_t addr) 134 { 135 db_watchpoint_t watch; 136 db_watchpoint_t *prev; 137 138 for (prev = &db_watchpoint_list; 139 (watch = *prev) != 0; 140 prev = &watch->link) 141 if (db_map_equal(watch->map, map) && 142 (watch->loaddr <= addr) && 143 (addr < watch->hiaddr)) { 144 *prev = watch->link; 145 db_watchpoint_free(watch); 146 return; 147 } 148 149 db_printf("Not set.\n"); 150 } 151 152 void 153 db_list_watchpoints(void) 154 { 155 db_watchpoint_t watch; 156 157 if (db_watchpoint_list == 0) { 158 db_printf("No watchpoints set\n"); 159 return; 160 } 161 162 db_printf(" Map Address Size\n"); 163 for (watch = db_watchpoint_list; watch != 0; watch = watch->link) 164 db_printf("%s%p %8lx %lx\n", 165 db_map_current(watch->map) ? "*" : " ", 166 watch->map, (long)watch->loaddr, 167 (long)(watch->hiaddr - watch->loaddr)); 168 } 169 170 /* Delete watchpoint */ 171 /*ARGSUSED*/ 172 void 173 db_deletewatch_cmd(db_expr_t addr, bool have_addr, 174 db_expr_t count, const char *modif) 175 { 176 177 db_delete_watchpoint(db_map_addr(addr), addr); 178 } 179 180 /* Set watchpoint */ 181 /*ARGSUSED*/ 182 void 183 db_watchpoint_cmd(db_expr_t addr, bool have_addr, 184 db_expr_t count, const char *modif) 185 { 186 vsize_t size; 187 db_expr_t value; 188 189 if (db_expression(&value)) 190 size = (vsize_t) value; 191 else 192 size = 4; 193 db_skip_to_eol(); 194 195 db_set_watchpoint(db_map_addr(addr), addr, size); 196 } 197 198 /* list watchpoints */ 199 /*ARGSUSED*/ 200 void 201 db_listwatch_cmd(db_expr_t addr, bool have_addr, 202 db_expr_t count, const char *modif) 203 { 204 205 db_list_watchpoints(); 206 } 207 208 void 209 db_set_watchpoints(void) 210 { 211 db_watchpoint_t watch; 212 213 if (!db_watchpoints_inserted) { 214 for (watch = db_watchpoint_list; 215 watch != 0; 216 watch = watch->link) { 217 pmap_protect(watch->map->pmap, 218 trunc_page(watch->loaddr), 219 round_page(watch->hiaddr), 220 VM_PROT_READ); 221 pmap_update(watch->map->pmap); 222 } 223 224 db_watchpoints_inserted = true; 225 } 226 } 227 228 void 229 db_clear_watchpoints(void) 230 { 231 232 db_watchpoints_inserted = false; 233 } 234