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_break.c,v 1.4 1994/08/13 03:49:15 wollman Exp $ 27 */ 28 29 /* 30 * Author: David B. Golub, Carnegie Mellon University 31 * Date: 7/90 32 */ 33 /* 34 * Breakpoints. 35 */ 36 #include <sys/param.h> 37 #include <sys/systm.h> 38 #include <sys/proc.h> 39 #include <ddb/ddb.h> 40 41 #include <ddb/db_lex.h> 42 #include <ddb/db_break.h> 43 #include <ddb/db_access.h> 44 #include <ddb/db_sym.h> 45 #include <ddb/db_break.h> 46 47 #define NBREAKPOINTS 100 48 struct db_breakpoint db_break_table[NBREAKPOINTS]; 49 db_breakpoint_t db_next_free_breakpoint = &db_break_table[0]; 50 db_breakpoint_t db_free_breakpoints = 0; 51 db_breakpoint_t db_breakpoint_list = 0; 52 53 db_breakpoint_t 54 db_breakpoint_alloc() 55 { 56 register db_breakpoint_t bkpt; 57 58 if ((bkpt = db_free_breakpoints) != 0) { 59 db_free_breakpoints = bkpt->link; 60 return (bkpt); 61 } 62 if (db_next_free_breakpoint == &db_break_table[NBREAKPOINTS]) { 63 db_printf("All breakpoints used.\n"); 64 return (0); 65 } 66 bkpt = db_next_free_breakpoint; 67 db_next_free_breakpoint++; 68 69 return (bkpt); 70 } 71 72 void 73 db_breakpoint_free(bkpt) 74 register db_breakpoint_t bkpt; 75 { 76 bkpt->link = db_free_breakpoints; 77 db_free_breakpoints = bkpt; 78 } 79 80 void 81 db_set_breakpoint(map, addr, count) 82 vm_map_t map; 83 db_addr_t addr; 84 int count; 85 { 86 register db_breakpoint_t bkpt; 87 88 if (db_find_breakpoint(map, addr)) { 89 db_printf("Already set.\n"); 90 return; 91 } 92 93 bkpt = db_breakpoint_alloc(); 94 if (bkpt == 0) { 95 db_printf("Too many breakpoints.\n"); 96 return; 97 } 98 99 bkpt->map = map; 100 bkpt->address = addr; 101 bkpt->flags = 0; 102 bkpt->init_count = count; 103 bkpt->count = count; 104 105 bkpt->link = db_breakpoint_list; 106 db_breakpoint_list = bkpt; 107 } 108 109 void 110 db_delete_breakpoint(map, addr) 111 vm_map_t map; 112 db_addr_t addr; 113 { 114 register db_breakpoint_t bkpt; 115 register db_breakpoint_t *prev; 116 117 for (prev = &db_breakpoint_list; 118 (bkpt = *prev) != 0; 119 prev = &bkpt->link) { 120 if (db_map_equal(bkpt->map, map) && 121 (bkpt->address == addr)) { 122 *prev = bkpt->link; 123 break; 124 } 125 } 126 if (bkpt == 0) { 127 db_printf("Not set.\n"); 128 return; 129 } 130 131 db_breakpoint_free(bkpt); 132 } 133 134 db_breakpoint_t 135 db_find_breakpoint(map, addr) 136 vm_map_t map; 137 db_addr_t addr; 138 { 139 register db_breakpoint_t bkpt; 140 141 for (bkpt = db_breakpoint_list; 142 bkpt != 0; 143 bkpt = bkpt->link) 144 { 145 if (db_map_equal(bkpt->map, map) && 146 (bkpt->address == addr)) 147 return (bkpt); 148 } 149 return (0); 150 } 151 152 db_breakpoint_t 153 db_find_breakpoint_here(addr) 154 db_addr_t addr; 155 { 156 return db_find_breakpoint(db_map_addr(addr), addr); 157 } 158 159 boolean_t db_breakpoints_inserted = TRUE; 160 161 void 162 db_set_breakpoints() 163 { 164 register db_breakpoint_t bkpt; 165 166 if (!db_breakpoints_inserted) { 167 168 for (bkpt = db_breakpoint_list; 169 bkpt != 0; 170 bkpt = bkpt->link) 171 if (db_map_current(bkpt->map)) { 172 bkpt->bkpt_inst = db_get_value(bkpt->address, 173 BKPT_SIZE, 174 FALSE); 175 db_put_value(bkpt->address, 176 BKPT_SIZE, 177 BKPT_SET(bkpt->bkpt_inst)); 178 } 179 db_breakpoints_inserted = TRUE; 180 } 181 } 182 183 void 184 db_clear_breakpoints() 185 { 186 register db_breakpoint_t bkpt; 187 188 if (db_breakpoints_inserted) { 189 190 for (bkpt = db_breakpoint_list; 191 bkpt != 0; 192 bkpt = bkpt->link) 193 if (db_map_current(bkpt->map)) { 194 db_put_value(bkpt->address, BKPT_SIZE, bkpt->bkpt_inst); 195 } 196 db_breakpoints_inserted = FALSE; 197 } 198 } 199 200 /* 201 * Set a temporary breakpoint. 202 * The instruction is changed immediately, 203 * so the breakpoint does not have to be on the breakpoint list. 204 */ 205 db_breakpoint_t 206 db_set_temp_breakpoint(addr) 207 db_addr_t addr; 208 { 209 register db_breakpoint_t bkpt; 210 211 bkpt = db_breakpoint_alloc(); 212 if (bkpt == 0) { 213 db_printf("Too many breakpoints.\n"); 214 return 0; 215 } 216 217 bkpt->map = NULL; 218 bkpt->address = addr; 219 bkpt->flags = BKPT_TEMP; 220 bkpt->init_count = 1; 221 bkpt->count = 1; 222 223 bkpt->bkpt_inst = db_get_value(bkpt->address, BKPT_SIZE, FALSE); 224 db_put_value(bkpt->address, BKPT_SIZE, BKPT_SET(bkpt->bkpt_inst)); 225 return bkpt; 226 } 227 228 void 229 db_delete_temp_breakpoint(bkpt) 230 db_breakpoint_t bkpt; 231 { 232 db_put_value(bkpt->address, BKPT_SIZE, bkpt->bkpt_inst); 233 db_breakpoint_free(bkpt); 234 } 235 236 /* 237 * List breakpoints. 238 */ 239 void 240 db_list_breakpoints() 241 { 242 register db_breakpoint_t bkpt; 243 244 if (db_breakpoint_list == 0) { 245 db_printf("No breakpoints set\n"); 246 return; 247 } 248 249 db_printf(" Map Count Address\n"); 250 for (bkpt = db_breakpoint_list; 251 bkpt != 0; 252 bkpt = bkpt->link) 253 { 254 db_printf("%s%8x %5d ", 255 db_map_current(bkpt->map) ? "*" : " ", 256 bkpt->map, bkpt->init_count); 257 db_printsym(bkpt->address, DB_STGY_PROC); 258 db_printf("\n"); 259 } 260 } 261 262 /* Delete breakpoint */ 263 /*ARGSUSED*/ 264 void 265 db_delete_cmd(addr, have_addr, count, modif) 266 db_expr_t addr; 267 int have_addr; 268 db_expr_t count; 269 char * modif; 270 { 271 db_delete_breakpoint(db_map_addr(addr), (db_addr_t)addr); 272 } 273 274 /* Set breakpoint with skip count */ 275 /*ARGSUSED*/ 276 void 277 db_breakpoint_cmd(addr, have_addr, count, modif) 278 db_expr_t addr; 279 int have_addr; 280 db_expr_t count; 281 char * modif; 282 { 283 if (count == -1) 284 count = 1; 285 286 db_set_breakpoint(db_map_addr(addr), (db_addr_t)addr, count); 287 } 288 289 /* list breakpoints */ 290 void 291 db_listbreak_cmd(db_expr_t dummy1, int dummy2, db_expr_t dummy3, char *dummy4) 292 { 293 db_list_breakpoints(); 294 } 295 296 #include <vm/vm_kern.h> 297 298 /* 299 * We want ddb to be usable before most of the kernel has been 300 * initialized. In particular, current_thread() or kernel_map 301 * (or both) may be null. 302 */ 303 304 boolean_t 305 db_map_equal(map1, map2) 306 vm_map_t map1, map2; 307 { 308 return ((map1 == map2) || 309 ((map1 == NULL) && (map2 == kernel_map)) || 310 ((map1 == kernel_map) && (map2 == NULL))); 311 } 312 313 boolean_t 314 db_map_current(map) 315 vm_map_t map; 316 { 317 #if 0 318 thread_t thread; 319 320 return ((map == NULL) || 321 (map == kernel_map) || 322 (((thread = current_thread()) != NULL) && 323 (map == thread->task->map))); 324 #else 325 return (1); 326 #endif 327 } 328 329 vm_map_t 330 db_map_addr(addr) 331 vm_offset_t addr; 332 { 333 #if 0 334 thread_t thread; 335 336 /* 337 * We want to return kernel_map for all 338 * non-user addresses, even when debugging 339 * kernel tasks with their own maps. 340 */ 341 342 if ((VM_MIN_ADDRESS <= addr) && 343 (addr < VM_MAX_ADDRESS) && 344 ((thread = current_thread()) != NULL)) 345 return thread->task->map; 346 else 347 #endif 348 return kernel_map; 349 } 350