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