1 /* $OpenBSD: db_break.c,v 1.12 2002/05/16 13:01:41 art Exp $ */ 2 /* $NetBSD: db_break.c,v 1.7 1996/03/30 22:30:03 christos Exp $ */ 3 4 /* 5 * Mach Operating System 6 * Copyright (c) 1993,1992,1991,1990 Carnegie Mellon University 7 * All Rights Reserved. 8 * 9 * Permission to use, copy, modify and distribute this software and its 10 * documentation is hereby granted, provided that both the copyright 11 * notice and this permission notice appear in all copies of the 12 * software, derivative works or modified versions, and any portions 13 * thereof, and that both notices appear in supporting documentation. 14 * 15 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 16 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR 17 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 18 * 19 * Carnegie Mellon requests users of this software to return to 20 * 21 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 22 * School of Computer Science 23 * Carnegie Mellon University 24 * Pittsburgh PA 15213-3890 25 * 26 * any improvements or extensions that they make and grant Carnegie Mellon 27 * the rights to redistribute these changes. 28 * 29 * Author: David B. Golub, Carnegie Mellon University 30 * Date: 7/90 31 */ 32 33 /* 34 * Breakpoints. 35 */ 36 #include <sys/param.h> 37 #include <sys/proc.h> 38 39 #include <uvm/uvm_extern.h> 40 41 #include <machine/db_machdep.h> /* type definitions */ 42 43 #include <ddb/db_lex.h> 44 #include <ddb/db_access.h> 45 #include <ddb/db_sym.h> 46 #include <ddb/db_break.h> 47 #include <ddb/db_output.h> 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 struct vm_map *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 #ifdef DB_VALID_BREAKPOINT 96 if (!DB_VALID_BREAKPOINT(addr)) { 97 db_printf("Not a valid address for a breakpoint.\n"); 98 return; 99 } 100 #endif 101 102 bkpt = db_breakpoint_alloc(); 103 if (bkpt == 0) { 104 db_printf("Too many breakpoints.\n"); 105 return; 106 } 107 108 bkpt->map = map; 109 bkpt->address = addr; 110 bkpt->flags = 0; 111 bkpt->init_count = count; 112 bkpt->count = count; 113 114 bkpt->link = db_breakpoint_list; 115 db_breakpoint_list = bkpt; 116 } 117 118 void 119 db_delete_breakpoint(map, addr) 120 struct vm_map *map; 121 db_addr_t addr; 122 { 123 register db_breakpoint_t bkpt; 124 register db_breakpoint_t *prev; 125 126 for (prev = &db_breakpoint_list; 127 (bkpt = *prev) != 0; 128 prev = &bkpt->link) { 129 if (db_map_equal(bkpt->map, map) && 130 (bkpt->address == addr)) { 131 *prev = bkpt->link; 132 break; 133 } 134 } 135 if (bkpt == 0) { 136 db_printf("Not set.\n"); 137 return; 138 } 139 140 db_breakpoint_free(bkpt); 141 } 142 143 db_breakpoint_t 144 db_find_breakpoint(map, addr) 145 struct vm_map *map; 146 db_addr_t addr; 147 { 148 register db_breakpoint_t bkpt; 149 150 for (bkpt = db_breakpoint_list; 151 bkpt != 0; 152 bkpt = bkpt->link) 153 { 154 if (db_map_equal(bkpt->map, map) && 155 (bkpt->address == addr)) 156 return (bkpt); 157 } 158 return (0); 159 } 160 161 db_breakpoint_t 162 db_find_breakpoint_here(addr) 163 db_addr_t addr; 164 { 165 return db_find_breakpoint(db_map_addr(addr), addr); 166 } 167 168 boolean_t db_breakpoints_inserted = TRUE; 169 170 void 171 db_set_breakpoints() 172 { 173 register db_breakpoint_t bkpt; 174 175 if (!db_breakpoints_inserted) { 176 177 for (bkpt = db_breakpoint_list; 178 bkpt != 0; 179 bkpt = bkpt->link) 180 if (db_map_current(bkpt->map)) { 181 bkpt->bkpt_inst = db_get_value(bkpt->address, BKPT_SIZE, 182 FALSE); 183 db_put_value(bkpt->address, BKPT_SIZE, 184 BKPT_SET(bkpt->bkpt_inst)); 185 } 186 db_breakpoints_inserted = TRUE; 187 } 188 } 189 190 void 191 db_clear_breakpoints() 192 { 193 register db_breakpoint_t bkpt; 194 195 if (db_breakpoints_inserted) { 196 197 for (bkpt = db_breakpoint_list; 198 bkpt != 0; 199 bkpt = bkpt->link) 200 if (db_map_current(bkpt->map)) { 201 db_put_value(bkpt->address, BKPT_SIZE, bkpt->bkpt_inst); 202 } 203 db_breakpoints_inserted = FALSE; 204 } 205 } 206 207 /* 208 * Set a temporary breakpoint. 209 * The instruction is changed immediately, 210 * so the breakpoint does not have to be on the breakpoint list. 211 */ 212 db_breakpoint_t 213 db_set_temp_breakpoint(addr) 214 db_addr_t addr; 215 { 216 db_breakpoint_t bkpt; 217 218 #ifdef DB_VALID_BREAKPOINT 219 if (!DB_VALID_BREAKPOINT(addr)) { 220 db_printf("Not a valid address for a breakpoint.\n"); 221 return (0); 222 } 223 #endif 224 225 bkpt = db_breakpoint_alloc(); 226 if (bkpt == 0) { 227 db_printf("Too many breakpoints.\n"); 228 return (0); 229 } 230 231 bkpt->map = NULL; 232 bkpt->address = addr; 233 bkpt->flags = BKPT_TEMP; 234 bkpt->init_count = 1; 235 bkpt->count = 1; 236 237 bkpt->bkpt_inst = db_get_value(bkpt->address, BKPT_SIZE, FALSE); 238 db_put_value(bkpt->address, BKPT_SIZE, BKPT_SET(bkpt->bkpt_inst)); 239 return bkpt; 240 } 241 242 void 243 db_delete_temp_breakpoint(bkpt) 244 db_breakpoint_t bkpt; 245 { 246 db_put_value(bkpt->address, BKPT_SIZE, bkpt->bkpt_inst); 247 db_breakpoint_free(bkpt); 248 } 249 250 /* 251 * List breakpoints. 252 */ 253 void 254 db_list_breakpoints() 255 { 256 register db_breakpoint_t bkpt; 257 258 if (db_breakpoint_list == 0) { 259 db_printf("No breakpoints set\n"); 260 return; 261 } 262 263 db_printf(" Map Count Address\n"); 264 for (bkpt = db_breakpoint_list; 265 bkpt != 0; 266 bkpt = bkpt->link) 267 { 268 db_printf("%s%p %5d ", 269 db_map_current(bkpt->map) ? "*" : " ", 270 bkpt->map, bkpt->init_count); 271 db_printsym(bkpt->address, DB_STGY_PROC, db_printf); 272 db_printf("\n"); 273 } 274 } 275 276 /* Delete breakpoint */ 277 /*ARGSUSED*/ 278 void 279 db_delete_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 db_delete_breakpoint(db_map_addr(addr), (db_addr_t)addr); 286 } 287 288 /* Set breakpoint with skip count */ 289 /*ARGSUSED*/ 290 void 291 db_breakpoint_cmd(addr, have_addr, count, modif) 292 db_expr_t addr; 293 int have_addr; 294 db_expr_t count; 295 char * modif; 296 { 297 if (count == -1) 298 count = 1; 299 300 db_set_breakpoint(db_map_addr(addr), (db_addr_t)addr, count); 301 } 302 303 /* list breakpoints */ 304 /*ARGSUSED*/ 305 void 306 db_listbreak_cmd(addr, have_addr, count, modif) 307 db_expr_t addr; 308 int have_addr; 309 db_expr_t count; 310 char * modif; 311 { 312 db_list_breakpoints(); 313 } 314 315 /* 316 * We want ddb to be usable before most of the kernel has been 317 * initialized. In particular, current_thread() or kernel_map 318 * (or both) may be null. 319 */ 320 321 boolean_t 322 db_map_equal(map1, map2) 323 struct vm_map *map1, *map2; 324 { 325 return ((map1 == map2) || 326 ((map1 == NULL) && (map2 == kernel_map)) || 327 ((map1 == kernel_map) && (map2 == NULL))); 328 } 329 330 boolean_t 331 db_map_current(map) 332 struct vm_map *map; 333 { 334 #if 0 335 thread_t thread; 336 337 return ((map == NULL) || 338 (map == kernel_map) || 339 (((thread = current_thread()) != NULL) && 340 (map == thread->proc->map))); 341 #else 342 return (1); 343 #endif 344 } 345 346 struct vm_map * 347 db_map_addr(addr) 348 vaddr_t addr; 349 { 350 #if 0 351 thread_t thread; 352 353 /* 354 * We want to return kernel_map for all 355 * non-user addresses, even when debugging 356 * kernel tasks with their own maps. 357 */ 358 359 if ((VM_MIN_ADDRESS <= addr) && 360 (addr < VM_MAX_ADDRESS) && 361 ((thread = current_thread()) != NULL)) 362 return thread->proc->map; 363 else 364 #endif 365 return kernel_map; 366 } 367