1 /* $OpenBSD: db_break.c,v 1.14 2010/11/27 19:59:11 miod Exp $ */ 2 /* $NetBSD: db_break.c,v 1.7 1996/03/30 22:30:03 christos Exp $ */ 3 4 /* 5 * Mach Operating System 6 * Copyright (c) 1993,1992,1991,1990 Carnegie Mellon University 7 * All Rights Reserved. 8 * 9 * Permission to use, copy, modify and distribute this software and its 10 * documentation is hereby granted, provided that both the copyright 11 * notice and this permission notice appear in all copies of the 12 * software, derivative works or modified versions, and any portions 13 * thereof, and that both notices appear in supporting documentation. 14 * 15 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 16 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR 17 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 18 * 19 * Carnegie Mellon requests users of this software to return to 20 * 21 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 22 * School of Computer Science 23 * Carnegie Mellon University 24 * Pittsburgh PA 15213-3890 25 * 26 * any improvements or extensions that they make and grant Carnegie Mellon 27 * the rights to redistribute these changes. 28 * 29 * Author: David B. Golub, Carnegie Mellon University 30 * Date: 7/90 31 */ 32 33 /* 34 * Breakpoints. 35 */ 36 #include <sys/param.h> 37 #include <sys/proc.h> 38 39 #include <uvm/uvm_extern.h> 40 41 #include <machine/db_machdep.h> /* type definitions */ 42 43 #include <ddb/db_lex.h> 44 #include <ddb/db_access.h> 45 #include <ddb/db_sym.h> 46 #include <ddb/db_break.h> 47 #include <ddb/db_output.h> 48 49 #define NBREAKPOINTS 100 50 struct db_breakpoint db_break_table[NBREAKPOINTS]; 51 db_breakpoint_t db_next_free_breakpoint = &db_break_table[0]; 52 db_breakpoint_t db_free_breakpoints = 0; 53 db_breakpoint_t db_breakpoint_list = 0; 54 55 db_breakpoint_t 56 db_breakpoint_alloc(void) 57 { 58 db_breakpoint_t bkpt; 59 60 if ((bkpt = db_free_breakpoints) != 0) { 61 db_free_breakpoints = bkpt->link; 62 return (bkpt); 63 } 64 if (db_next_free_breakpoint == &db_break_table[NBREAKPOINTS]) { 65 db_printf("All breakpoints used.\n"); 66 return (0); 67 } 68 bkpt = db_next_free_breakpoint; 69 db_next_free_breakpoint++; 70 71 return (bkpt); 72 } 73 74 void 75 db_breakpoint_free(db_breakpoint_t bkpt) 76 { 77 bkpt->link = db_free_breakpoints; 78 db_free_breakpoints = bkpt; 79 } 80 81 void 82 db_set_breakpoint(db_addr_t addr, int count) 83 { 84 db_breakpoint_t bkpt; 85 86 if (db_find_breakpoint(addr)) { 87 db_printf("Already set.\n"); 88 return; 89 } 90 91 #ifdef DB_VALID_BREAKPOINT 92 if (!DB_VALID_BREAKPOINT(addr)) { 93 db_printf("Not a valid address for a breakpoint.\n"); 94 return; 95 } 96 #endif 97 98 bkpt = db_breakpoint_alloc(); 99 if (bkpt == 0) { 100 db_printf("Too many breakpoints.\n"); 101 return; 102 } 103 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 113 void 114 db_delete_breakpoint(db_addr_t addr) 115 { 116 db_breakpoint_t bkpt; 117 db_breakpoint_t *prev; 118 119 for (prev = &db_breakpoint_list; (bkpt = *prev) != 0; 120 prev = &bkpt->link) { 121 if (bkpt->address == addr) { 122 *prev = bkpt->link; 123 break; 124 } 125 } 126 if (bkpt == 0) { 127 db_printf("Not set.\n"); 128 return; 129 } 130 131 db_breakpoint_free(bkpt); 132 } 133 134 db_breakpoint_t 135 db_find_breakpoint(db_addr_t addr) 136 { 137 db_breakpoint_t bkpt; 138 139 for (bkpt = db_breakpoint_list; bkpt != 0; bkpt = bkpt->link) 140 if (bkpt->address == addr) 141 return (bkpt); 142 143 return (0); 144 } 145 146 boolean_t db_breakpoints_inserted = TRUE; 147 148 void 149 db_set_breakpoints(void) 150 { 151 db_breakpoint_t bkpt; 152 153 if (!db_breakpoints_inserted) { 154 for (bkpt = db_breakpoint_list; bkpt != 0; bkpt = bkpt->link) { 155 bkpt->bkpt_inst = 156 db_get_value(bkpt->address, BKPT_SIZE, FALSE); 157 db_put_value(bkpt->address, BKPT_SIZE, 158 BKPT_SET(bkpt->bkpt_inst)); 159 } 160 db_breakpoints_inserted = TRUE; 161 } 162 } 163 164 void 165 db_clear_breakpoints(void) 166 { 167 db_breakpoint_t bkpt; 168 169 if (db_breakpoints_inserted) { 170 for (bkpt = db_breakpoint_list; bkpt != 0; bkpt = bkpt->link) 171 db_put_value(bkpt->address, BKPT_SIZE, bkpt->bkpt_inst); 172 db_breakpoints_inserted = FALSE; 173 } 174 } 175 176 /* 177 * Set a temporary breakpoint. 178 * The instruction is changed immediately, 179 * so the breakpoint does not have to be on the breakpoint list. 180 */ 181 db_breakpoint_t 182 db_set_temp_breakpoint(db_addr_t addr) 183 { 184 db_breakpoint_t bkpt; 185 186 #ifdef DB_VALID_BREAKPOINT 187 if (!DB_VALID_BREAKPOINT(addr)) { 188 db_printf("Not a valid address for a breakpoint.\n"); 189 return (0); 190 } 191 #endif 192 193 bkpt = db_breakpoint_alloc(); 194 if (bkpt == 0) { 195 db_printf("Too many breakpoints.\n"); 196 return (0); 197 } 198 199 bkpt->address = addr; 200 bkpt->flags = BKPT_TEMP; 201 bkpt->init_count = 1; 202 bkpt->count = 1; 203 204 bkpt->bkpt_inst = db_get_value(bkpt->address, BKPT_SIZE, FALSE); 205 db_put_value(bkpt->address, BKPT_SIZE, BKPT_SET(bkpt->bkpt_inst)); 206 return bkpt; 207 } 208 209 void 210 db_delete_temp_breakpoint(db_breakpoint_t bkpt) 211 { 212 db_put_value(bkpt->address, BKPT_SIZE, bkpt->bkpt_inst); 213 db_breakpoint_free(bkpt); 214 } 215 216 /* 217 * List breakpoints. 218 */ 219 void 220 db_list_breakpoints(void) 221 { 222 db_breakpoint_t bkpt; 223 224 if (db_breakpoint_list == NULL) { 225 db_printf("No breakpoints set\n"); 226 return; 227 } 228 229 db_printf(" Count Address\n"); 230 for (bkpt = db_breakpoint_list; bkpt != 0; bkpt = bkpt->link) { 231 db_printf(" %5d ", bkpt->init_count); 232 db_printsym(bkpt->address, DB_STGY_PROC, db_printf); 233 db_printf("\n"); 234 } 235 } 236 237 /* Delete breakpoint */ 238 /*ARGSUSED*/ 239 void 240 db_delete_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif) 241 { 242 db_delete_breakpoint((db_addr_t)addr); 243 } 244 245 /* Set breakpoint with skip count */ 246 /*ARGSUSED*/ 247 void 248 db_breakpoint_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif) 249 { 250 if (count == -1) 251 count = 1; 252 253 db_set_breakpoint((db_addr_t)addr, count); 254 } 255 256 /* list breakpoints */ 257 /*ARGSUSED*/ 258 void 259 db_listbreak_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif) 260 { 261 db_list_breakpoints(); 262 } 263