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