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