db_break.c revision 2056
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.3 1993/11/25 01:30:03 wollman Exp $ 27 */ 28 29/* 30 * Author: David B. Golub, Carnegie Mellon University 31 * Date: 7/90 32 */ 33/* 34 * Breakpoints. 35 */ 36#include <sys/param.h> 37#include <sys/systm.h> 38#include <sys/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 47extern boolean_t db_map_equal(); 48extern boolean_t db_map_current(); 49extern vm_map_t db_map_addr(); 50 51#define NBREAKPOINTS 100 52struct db_breakpoint db_break_table[NBREAKPOINTS]; 53db_breakpoint_t db_next_free_breakpoint = &db_break_table[0]; 54db_breakpoint_t db_free_breakpoints = 0; 55db_breakpoint_t db_breakpoint_list = 0; 56 57db_breakpoint_t 58db_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 76void 77db_breakpoint_free(bkpt) 78 register db_breakpoint_t bkpt; 79{ 80 bkpt->link = db_free_breakpoints; 81 db_free_breakpoints = bkpt; 82} 83 84void 85db_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 113void 114db_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 138db_breakpoint_t 139db_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 156db_breakpoint_t 157db_find_breakpoint_here(addr) 158 db_addr_t addr; 159{ 160 return db_find_breakpoint(db_map_addr(addr), addr); 161} 162 163boolean_t db_breakpoints_inserted = TRUE; 164 165void 166db_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 187void 188db_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 */ 209db_breakpoint_t 210db_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 232void 233db_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 */ 243void 244db_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*/ 268void 269db_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*/ 280void 281db_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 */ 294void 295db_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 308boolean_t 309db_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 317boolean_t 318db_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 333vm_map_t 334db_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