db_break.c revision 623
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$ 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 "proc.h" 38#include <machine/db_machdep.h> /* type definitions */ 39 40#include <ddb/db_lex.h> 41#include <ddb/db_break.h> 42#include <ddb/db_access.h> 43#include <ddb/db_sym.h> 44#include <ddb/db_break.h> 45 46extern boolean_t db_map_equal(); 47extern boolean_t db_map_current(); 48extern vm_map_t db_map_addr(); 49 50#define NBREAKPOINTS 100 51struct db_breakpoint db_break_table[NBREAKPOINTS]; 52db_breakpoint_t db_next_free_breakpoint = &db_break_table[0]; 53db_breakpoint_t db_free_breakpoints = 0; 54db_breakpoint_t db_breakpoint_list = 0; 55 56db_breakpoint_t 57db_breakpoint_alloc() 58{ 59 register 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 75void 76db_breakpoint_free(bkpt) 77 register db_breakpoint_t bkpt; 78{ 79 bkpt->link = db_free_breakpoints; 80 db_free_breakpoints = bkpt; 81} 82 83void 84db_set_breakpoint(map, addr, count) 85 vm_map_t map; 86 db_addr_t addr; 87 int count; 88{ 89 register 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 112void 113db_delete_breakpoint(map, addr) 114 vm_map_t map; 115 db_addr_t addr; 116{ 117 register db_breakpoint_t bkpt; 118 register 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 137db_breakpoint_t 138db_find_breakpoint(map, addr) 139 vm_map_t map; 140 db_addr_t addr; 141{ 142 register 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 155db_breakpoint_t 156db_find_breakpoint_here(addr) 157 db_addr_t addr; 158{ 159 return db_find_breakpoint(db_map_addr(addr), addr); 160} 161 162boolean_t db_breakpoints_inserted = TRUE; 163 164void 165db_set_breakpoints() 166{ 167 register 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 186void 187db_clear_breakpoints() 188{ 189 register 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 * Set a temporary breakpoint. 205 * The instruction is changed immediately, 206 * so the breakpoint does not have to be on the breakpoint list. 207 */ 208db_breakpoint_t 209db_set_temp_breakpoint(addr) 210 db_addr_t addr; 211{ 212 register db_breakpoint_t bkpt; 213 214 bkpt = db_breakpoint_alloc(); 215 if (bkpt == 0) { 216 db_printf("Too many breakpoints.\n"); 217 return 0; 218 } 219 220 bkpt->map = NULL; 221 bkpt->address = addr; 222 bkpt->flags = BKPT_TEMP; 223 bkpt->init_count = 1; 224 bkpt->count = 1; 225 226 bkpt->bkpt_inst = db_get_value(bkpt->address, BKPT_SIZE, FALSE); 227 db_put_value(bkpt->address, BKPT_SIZE, BKPT_SET(bkpt->bkpt_inst)); 228 return bkpt; 229} 230 231void 232db_delete_temp_breakpoint(bkpt) 233 db_breakpoint_t bkpt; 234{ 235 db_put_value(bkpt->address, BKPT_SIZE, bkpt->bkpt_inst); 236 db_breakpoint_free(bkpt); 237} 238 239/* 240 * List breakpoints. 241 */ 242void 243db_list_breakpoints() 244{ 245 register db_breakpoint_t bkpt; 246 247 if (db_breakpoint_list == 0) { 248 db_printf("No breakpoints set\n"); 249 return; 250 } 251 252 db_printf(" Map Count Address\n"); 253 for (bkpt = db_breakpoint_list; 254 bkpt != 0; 255 bkpt = bkpt->link) 256 { 257 db_printf("%s%8x %5d ", 258 db_map_current(bkpt->map) ? "*" : " ", 259 bkpt->map, bkpt->init_count); 260 db_printsym(bkpt->address, DB_STGY_PROC); 261 db_printf("\n"); 262 } 263} 264 265/* Delete breakpoint */ 266/*ARGSUSED*/ 267void 268db_delete_cmd(addr, have_addr, count, modif) 269 db_expr_t addr; 270 int have_addr; 271 db_expr_t count; 272 char * modif; 273{ 274 db_delete_breakpoint(db_map_addr(addr), (db_addr_t)addr); 275} 276 277/* Set breakpoint with skip count */ 278/*ARGSUSED*/ 279void 280db_breakpoint_cmd(addr, have_addr, count, modif) 281 db_expr_t addr; 282 int have_addr; 283 db_expr_t count; 284 char * modif; 285{ 286 if (count == -1) 287 count = 1; 288 289 db_set_breakpoint(db_map_addr(addr), (db_addr_t)addr, count); 290} 291 292/* list breakpoints */ 293void 294db_listbreak_cmd() 295{ 296 db_list_breakpoints(); 297} 298 299#include <vm/vm_kern.h> 300 301/* 302 * We want ddb to be usable before most of the kernel has been 303 * initialized. In particular, current_thread() or kernel_map 304 * (or both) may be null. 305 */ 306 307boolean_t 308db_map_equal(map1, map2) 309 vm_map_t map1, map2; 310{ 311 return ((map1 == map2) || 312 ((map1 == NULL) && (map2 == kernel_map)) || 313 ((map1 == kernel_map) && (map2 == NULL))); 314} 315 316boolean_t 317db_map_current(map) 318 vm_map_t map; 319{ 320#if 0 321 thread_t thread; 322 323 return ((map == NULL) || 324 (map == kernel_map) || 325 (((thread = current_thread()) != NULL) && 326 (map == thread->task->map))); 327#else 328 return (1); 329#endif 330} 331 332vm_map_t 333db_map_addr(addr) 334 vm_offset_t addr; 335{ 336#if 0 337 thread_t thread; 338 339 /* 340 * We want to return kernel_map for all 341 * non-user addresses, even when debugging 342 * kernel tasks with their own maps. 343 */ 344 345 if ((VM_MIN_ADDRESS <= addr) && 346 (addr < VM_MAX_ADDRESS) && 347 ((thread = current_thread()) != NULL)) 348 return thread->task->map; 349 else 350#endif 351 return kernel_map; 352} 353