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