db_break.c revision 36735
1192303Sbrueffer/* 2176698Sbrueffer * Mach Operating System 3176698Sbrueffer * Copyright (c) 1991,1990 Carnegie Mellon University 4176698Sbrueffer * All Rights Reserved. 5176698Sbrueffer * 6176698Sbrueffer * Permission to use, copy, modify and distribute this software and its 7176698Sbrueffer * documentation is hereby granted, provided that both the copyright 8176698Sbrueffer * notice and this permission notice appear in all copies of the 9176698Sbrueffer * software, derivative works or modified versions, and any portions 10176698Sbrueffer * thereof, and that both notices appear in supporting documentation. 11176698Sbrueffer * 12176698Sbrueffer * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS 13176698Sbrueffer * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR 14176698Sbrueffer * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 15176698Sbrueffer * 16176698Sbrueffer * Carnegie Mellon requests users of this software to return to 17176698Sbrueffer * 18176698Sbrueffer * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 19176698Sbrueffer * School of Computer Science 20176698Sbrueffer * Carnegie Mellon University 21176698Sbrueffer * Pittsburgh PA 15213-3890 22176698Sbrueffer * 23176698Sbrueffer * any improvements or extensions that they make and grant Carnegie the 24176698Sbrueffer * rights to redistribute these changes. 25176698Sbrueffer * 26176698Sbrueffer * $Id: db_break.c,v 1.14 1997/06/14 11:52:36 bde Exp $ 27176698Sbrueffer */ 28176698Sbrueffer 29176698Sbrueffer/* 30176698Sbrueffer * Author: David B. Golub, Carnegie Mellon University 31176698Sbrueffer * Date: 7/90 32227750Smiwi */ 33176698Sbrueffer/* 34176698Sbrueffer * Breakpoints. 35176698Sbrueffer */ 36176698Sbrueffer#include <sys/param.h> 37176698Sbrueffer 38176698Sbrueffer#include <vm/vm.h> 39176698Sbrueffer#include <vm/vm_kern.h> 40176698Sbrueffer 41176698Sbrueffer#include <ddb/ddb.h> 42176698Sbrueffer#include <ddb/db_break.h> 43227750Smiwi#include <ddb/db_access.h> 44227750Smiwi#include <ddb/db_sym.h> 45176698Sbrueffer 46176698Sbrueffer#define NBREAKPOINTS 100 47192141Sbruefferstatic struct db_breakpoint db_break_table[NBREAKPOINTS]; 48192141Sbruefferstatic db_breakpoint_t db_next_free_breakpoint = &db_break_table[0]; 49192141Sbruefferstatic db_breakpoint_t db_free_breakpoints = 0; 50192141Sbruefferstatic db_breakpoint_t db_breakpoint_list = 0; 51192141Sbrueffer 52192141Sbruefferstatic db_breakpoint_t db_breakpoint_alloc __P((void)); 53192141Sbruefferstatic void db_breakpoint_free __P((db_breakpoint_t bkpt)); 54176698Sbruefferstatic void db_delete_breakpoint __P((vm_map_t map, db_addr_t addr)); 55176698Sbruefferstatic db_breakpoint_t db_find_breakpoint __P((vm_map_t map, db_addr_t addr)); 56176698Sbruefferstatic void db_list_breakpoints __P((void)); 57176698Sbruefferstatic void db_set_breakpoint __P((vm_map_t map, db_addr_t addr, 58176698Sbrueffer int count)); 59176698Sbrueffer#ifdef notused 60176698Sbruefferstatic db_breakpoint_t db_set_temp_breakpoint __P((db_addr_t addr)); 61176698Sbruefferstatic void db_delete_temp_breakpoint __P((db_breakpoint_t bkpt)); 62176698Sbrueffer#endif 63176698Sbrueffer 64176698Sbruefferstatic db_breakpoint_t 65176698Sbruefferdb_breakpoint_alloc() 66176698Sbrueffer{ 67176698Sbrueffer register db_breakpoint_t bkpt; 68176698Sbrueffer 69176698Sbrueffer if ((bkpt = db_free_breakpoints) != 0) { 70176698Sbrueffer db_free_breakpoints = bkpt->link; 71176698Sbrueffer return (bkpt); 72176698Sbrueffer } 73176698Sbrueffer if (db_next_free_breakpoint == &db_break_table[NBREAKPOINTS]) { 74176698Sbrueffer db_printf("All breakpoints used.\n"); 75176698Sbrueffer return (0); 76176698Sbrueffer } 77176698Sbrueffer bkpt = db_next_free_breakpoint; 78176698Sbrueffer db_next_free_breakpoint++; 79176698Sbrueffer 80176698Sbrueffer return (bkpt); 81176698Sbrueffer} 82176698Sbrueffer 83176698Sbruefferstatic void 84176698Sbruefferdb_breakpoint_free(bkpt) 85192303Sbrueffer register db_breakpoint_t bkpt; 86176698Sbrueffer{ 87176698Sbrueffer bkpt->link = db_free_breakpoints; 88176698Sbrueffer db_free_breakpoints = bkpt; 89} 90 91static void 92db_set_breakpoint(map, addr, count) 93 vm_map_t map; 94 db_addr_t addr; 95 int count; 96{ 97 register db_breakpoint_t bkpt; 98 99 if (db_find_breakpoint(map, addr)) { 100 db_printf("Already set.\n"); 101 return; 102 } 103 104 bkpt = db_breakpoint_alloc(); 105 if (bkpt == 0) { 106 db_printf("Too many breakpoints.\n"); 107 return; 108 } 109 110 bkpt->map = map; 111 bkpt->address = addr; 112 bkpt->flags = 0; 113 bkpt->init_count = count; 114 bkpt->count = count; 115 116 bkpt->link = db_breakpoint_list; 117 db_breakpoint_list = bkpt; 118} 119 120static void 121db_delete_breakpoint(map, addr) 122 vm_map_t map; 123 db_addr_t addr; 124{ 125 register db_breakpoint_t bkpt; 126 register db_breakpoint_t *prev; 127 128 for (prev = &db_breakpoint_list; 129 (bkpt = *prev) != 0; 130 prev = &bkpt->link) { 131 if (db_map_equal(bkpt->map, map) && 132 (bkpt->address == addr)) { 133 *prev = bkpt->link; 134 break; 135 } 136 } 137 if (bkpt == 0) { 138 db_printf("Not set.\n"); 139 return; 140 } 141 142 db_breakpoint_free(bkpt); 143} 144 145static db_breakpoint_t 146db_find_breakpoint(map, addr) 147 vm_map_t map; 148 db_addr_t addr; 149{ 150 register db_breakpoint_t bkpt; 151 152 for (bkpt = db_breakpoint_list; 153 bkpt != 0; 154 bkpt = bkpt->link) 155 { 156 if (db_map_equal(bkpt->map, map) && 157 (bkpt->address == addr)) 158 return (bkpt); 159 } 160 return (0); 161} 162 163db_breakpoint_t 164db_find_breakpoint_here(addr) 165 db_addr_t addr; 166{ 167 return db_find_breakpoint(db_map_addr(addr), addr); 168} 169 170static boolean_t db_breakpoints_inserted = TRUE; 171 172void 173db_set_breakpoints() 174{ 175 register db_breakpoint_t bkpt; 176 177 if (!db_breakpoints_inserted) { 178 179 for (bkpt = db_breakpoint_list; 180 bkpt != 0; 181 bkpt = bkpt->link) 182 if (db_map_current(bkpt->map)) { 183 bkpt->bkpt_inst = db_get_value(bkpt->address, 184 BKPT_SIZE, 185 FALSE); 186 db_put_value(bkpt->address, 187 BKPT_SIZE, 188 BKPT_SET(bkpt->bkpt_inst)); 189 } 190 db_breakpoints_inserted = TRUE; 191 } 192} 193 194void 195db_clear_breakpoints() 196{ 197 register db_breakpoint_t bkpt; 198 199 if (db_breakpoints_inserted) { 200 201 for (bkpt = db_breakpoint_list; 202 bkpt != 0; 203 bkpt = bkpt->link) 204 if (db_map_current(bkpt->map)) { 205 db_put_value(bkpt->address, BKPT_SIZE, bkpt->bkpt_inst); 206 } 207 db_breakpoints_inserted = FALSE; 208 } 209} 210 211#ifdef SOFTWARE_SSTEP 212/* 213 * Set a temporary breakpoint. 214 * The instruction is changed immediately, 215 * so the breakpoint does not have to be on the breakpoint list. 216 */ 217db_breakpoint_t 218db_set_temp_breakpoint(addr) 219 db_addr_t addr; 220{ 221 register db_breakpoint_t bkpt; 222 223 bkpt = db_breakpoint_alloc(); 224 if (bkpt == 0) { 225 db_printf("Too many breakpoints.\n"); 226 return 0; 227 } 228 229 bkpt->map = NULL; 230 bkpt->address = addr; 231 bkpt->flags = BKPT_TEMP; 232 bkpt->init_count = 1; 233 bkpt->count = 1; 234 235 bkpt->bkpt_inst = db_get_value(bkpt->address, BKPT_SIZE, FALSE); 236 db_put_value(bkpt->address, BKPT_SIZE, BKPT_SET(bkpt->bkpt_inst)); 237 return bkpt; 238} 239 240void 241db_delete_temp_breakpoint(bkpt) 242 db_breakpoint_t bkpt; 243{ 244 db_put_value(bkpt->address, BKPT_SIZE, bkpt->bkpt_inst); 245 db_breakpoint_free(bkpt); 246} 247 248#endif 249 250/* 251 * List breakpoints. 252 */ 253static void 254db_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%8x %5d ", 269 db_map_current(bkpt->map) ? "*" : " ", 270 bkpt->map, bkpt->init_count); 271 db_printsym(bkpt->address, DB_STGY_PROC); 272 db_printf("\n"); 273 } 274} 275 276/* Delete breakpoint */ 277/*ARGSUSED*/ 278void 279db_delete_cmd(addr, have_addr, count, modif) 280 db_expr_t addr; 281 boolean_t 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*/ 290void 291db_breakpoint_cmd(addr, have_addr, count, modif) 292 db_expr_t addr; 293 boolean_t 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 */ 304void 305db_listbreak_cmd(dummy1, dummy2, dummy3, dummy4) 306 db_expr_t dummy1; 307 boolean_t dummy2; 308 db_expr_t dummy3; 309 char * dummy4; 310{ 311 db_list_breakpoints(); 312} 313 314/* 315 * We want ddb to be usable before most of the kernel has been 316 * initialized. In particular, current_thread() or kernel_map 317 * (or both) may be null. 318 */ 319 320boolean_t 321db_map_equal(map1, map2) 322 vm_map_t map1, map2; 323{ 324 return ((map1 == map2) || 325 ((map1 == NULL) && (map2 == kernel_map)) || 326 ((map1 == kernel_map) && (map2 == NULL))); 327} 328 329boolean_t 330db_map_current(map) 331 vm_map_t map; 332{ 333#if 0 334 thread_t thread; 335 336 return ((map == NULL) || 337 (map == kernel_map) || 338 (((thread = current_thread()) != NULL) && 339 (map == thread->task->map))); 340#else 341 return (1); 342#endif 343} 344 345vm_map_t 346db_map_addr(addr) 347 vm_offset_t addr; 348{ 349#if 0 350 thread_t thread; 351 352 /* 353 * We want to return kernel_map for all 354 * non-user addresses, even when debugging 355 * kernel tasks with their own maps. 356 */ 357 358 if ((VM_MIN_ADDRESS <= addr) && 359 (addr < VM_MAX_ADDRESS) && 360 ((thread = current_thread()) != NULL)) 361 return thread->task->map; 362 else 363#endif 364 return kernel_map; 365} 366