1 /* $NetBSD: db_break.c,v 1.16 2001/11/12 22:54:04 lukem Exp $ */ 2 3 /* 4 * Mach Operating System 5 * Copyright (c) 1991,1990 Carnegie Mellon University 6 * All Rights Reserved. 7 * 8 * Permission to use, copy, modify and distribute this software and its 9 * documentation is hereby granted, provided that both the copyright 10 * notice and this permission notice appear in all copies of the 11 * software, derivative works or modified versions, and any portions 12 * thereof, and that both notices appear in supporting documentation. 13 * 14 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 15 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR 16 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 17 * 18 * Carnegie Mellon requests users of this software to return to 19 * 20 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 21 * School of Computer Science 22 * Carnegie Mellon University 23 * Pittsburgh PA 15213-3890 24 * 25 * any improvements or extensions that they make and grant Carnegie the 26 * rights to redistribute these changes. 27 * 28 * Author: David B. Golub, Carnegie Mellon University 29 * Date: 7/90 30 */ 31 32 /* 33 * Breakpoints. 34 */ 35 36 #include <sys/cdefs.h> 37 __KERNEL_RCSID(0, "$NetBSD: db_break.c,v 1.16 2001/11/12 22:54:04 lukem Exp $"); 38 39 #include <sys/param.h> 40 #include <sys/proc.h> 41 42 #include <machine/db_machdep.h> /* type definitions */ 43 44 #include <ddb/db_lex.h> 45 #include <ddb/db_access.h> 46 #include <ddb/db_sym.h> 47 #include <ddb/db_break.h> 48 #include <ddb/db_output.h> 49 50 #define NBREAKPOINTS 100 51 struct db_breakpoint db_break_table[NBREAKPOINTS]; 52 db_breakpoint_t db_next_free_breakpoint = &db_break_table[0]; 53 db_breakpoint_t db_free_breakpoints = 0; 54 db_breakpoint_t db_breakpoint_list = 0; 55 56 db_breakpoint_t 57 db_breakpoint_alloc() 58 { 59 db_breakpoint_t bkpt; 60 61 if ((bkpt = db_free_breakpoints) != 0) { 62 db_free_breakpoints = bkpt->link; 63 return (bkpt); 64 } 65 if (db_next_free_breakpoint == &db_break_table[NBREAKPOINTS]) { 66 db_printf("All breakpoints used.\n"); 67 return (0); 68 } 69 bkpt = db_next_free_breakpoint; 70 db_next_free_breakpoint++; 71 72 return (bkpt); 73 } 74 75 void 76 db_breakpoint_free(bkpt) 77 db_breakpoint_t bkpt; 78 { 79 bkpt->link = db_free_breakpoints; 80 db_free_breakpoints = bkpt; 81 } 82 83 void 84 db_set_breakpoint(map, addr, count) 85 struct vm_map *map; 86 db_addr_t addr; 87 int count; 88 { 89 db_breakpoint_t bkpt; 90 91 if (db_find_breakpoint(map, addr)) { 92 db_printf("Already set.\n"); 93 return; 94 } 95 96 bkpt = db_breakpoint_alloc(); 97 if (bkpt == 0) { 98 db_printf("Too many breakpoints.\n"); 99 return; 100 } 101 102 bkpt->map = map; 103 bkpt->address = addr; 104 bkpt->flags = 0; 105 bkpt->init_count = count; 106 bkpt->count = count; 107 108 bkpt->link = db_breakpoint_list; 109 db_breakpoint_list = bkpt; 110 } 111 112 void 113 db_delete_breakpoint(map, addr) 114 struct vm_map *map; 115 db_addr_t addr; 116 { 117 db_breakpoint_t bkpt; 118 db_breakpoint_t *prev; 119 120 for (prev = &db_breakpoint_list; 121 (bkpt = *prev) != 0; 122 prev = &bkpt->link) { 123 if (db_map_equal(bkpt->map, map) && 124 (bkpt->address == addr)) { 125 *prev = bkpt->link; 126 break; 127 } 128 } 129 if (bkpt == 0) { 130 db_printf("Not set.\n"); 131 return; 132 } 133 134 db_breakpoint_free(bkpt); 135 } 136 137 db_breakpoint_t 138 db_find_breakpoint(map, addr) 139 struct vm_map *map; 140 db_addr_t addr; 141 { 142 db_breakpoint_t bkpt; 143 144 for (bkpt = db_breakpoint_list; 145 bkpt != 0; 146 bkpt = bkpt->link) 147 { 148 if (db_map_equal(bkpt->map, map) && 149 (bkpt->address == addr)) 150 return (bkpt); 151 } 152 return (0); 153 } 154 155 db_breakpoint_t 156 db_find_breakpoint_here(addr) 157 db_addr_t addr; 158 { 159 return db_find_breakpoint(db_map_addr(addr), addr); 160 } 161 162 boolean_t db_breakpoints_inserted = TRUE; 163 164 void 165 db_set_breakpoints() 166 { 167 db_breakpoint_t bkpt; 168 169 if (!db_breakpoints_inserted) { 170 171 for (bkpt = db_breakpoint_list; 172 bkpt != 0; 173 bkpt = bkpt->link) 174 if (db_map_current(bkpt->map)) { 175 bkpt->bkpt_inst = db_get_value(bkpt->address, 176 BKPT_SIZE, 177 FALSE); 178 db_put_value(bkpt->address, 179 BKPT_SIZE, 180 BKPT_SET(bkpt->bkpt_inst)); 181 } 182 db_breakpoints_inserted = TRUE; 183 } 184 } 185 186 void 187 db_clear_breakpoints() 188 { 189 db_breakpoint_t bkpt; 190 191 if (db_breakpoints_inserted) { 192 193 for (bkpt = db_breakpoint_list; 194 bkpt != 0; 195 bkpt = bkpt->link) 196 if (db_map_current(bkpt->map)) { 197 db_put_value(bkpt->address, BKPT_SIZE, bkpt->bkpt_inst); 198 } 199 db_breakpoints_inserted = FALSE; 200 } 201 } 202 203 /* 204 * List breakpoints. 205 */ 206 void 207 db_list_breakpoints() 208 { 209 db_breakpoint_t bkpt; 210 211 if (db_breakpoint_list == 0) { 212 db_printf("No breakpoints set\n"); 213 return; 214 } 215 216 db_printf(" Map Count Address\n"); 217 for (bkpt = db_breakpoint_list; 218 bkpt != 0; 219 bkpt = bkpt->link) 220 { 221 db_printf("%s%p %5d ", 222 db_map_current(bkpt->map) ? "*" : " ", 223 bkpt->map, bkpt->init_count); 224 db_printsym(bkpt->address, DB_STGY_PROC, db_printf); 225 db_printf("\n"); 226 } 227 } 228 229 /* Delete breakpoint */ 230 /*ARGSUSED*/ 231 void 232 db_delete_cmd(addr, have_addr, count, modif) 233 db_expr_t addr; 234 int have_addr; 235 db_expr_t count; 236 char * modif; 237 { 238 db_delete_breakpoint(db_map_addr(addr), (db_addr_t)addr); 239 } 240 241 /* Set breakpoint with skip count */ 242 /*ARGSUSED*/ 243 void 244 db_breakpoint_cmd(addr, have_addr, count, modif) 245 db_expr_t addr; 246 int have_addr; 247 db_expr_t count; 248 char * modif; 249 { 250 if (count == -1) 251 count = 1; 252 253 db_set_breakpoint(db_map_addr(addr), (db_addr_t)addr, count); 254 } 255 256 /* list breakpoints */ 257 /*ARGSUSED*/ 258 void 259 db_listbreak_cmd(addr, have_addr, count, modif) 260 db_expr_t addr; 261 int have_addr; 262 db_expr_t count; 263 char * modif; 264 { 265 db_list_breakpoints(); 266 } 267 268 #include <uvm/uvm_extern.h> 269 270 /* 271 * We want ddb to be usable before most of the kernel has been 272 * initialized. In particular, current_thread() or kernel_map 273 * (or both) may be null. 274 */ 275 276 boolean_t 277 db_map_equal(map1, map2) 278 struct vm_map *map1; 279 struct vm_map *map2; 280 { 281 return ((map1 == map2) || 282 ((map1 == NULL) && (map2 == kernel_map)) || 283 ((map1 == kernel_map) && (map2 == NULL))); 284 } 285 286 boolean_t 287 db_map_current(map) 288 struct vm_map *map; 289 { 290 #if 0 291 thread_t thread; 292 293 return ((map == NULL) || 294 (map == kernel_map) || 295 (((thread = current_thread()) != NULL) && 296 (map == thread->task->map))); 297 #else 298 return (1); 299 #endif 300 } 301 302 struct vm_map * 303 db_map_addr(addr) 304 vaddr_t addr; 305 { 306 #if 0 307 thread_t thread; 308 309 /* 310 * We want to return kernel_map for all 311 * non-user addresses, even when debugging 312 * kernel tasks with their own maps. 313 */ 314 315 if ((VM_MIN_ADDRESS <= addr) && 316 (addr < VM_MAX_ADDRESS) && 317 ((thread = current_thread()) != NULL)) 318 return thread->task->map; 319 else 320 #endif 321 return kernel_map; 322 } 323