1 /* $OpenBSD: db_break.c,v 1.15 2014/07/08 13:02:57 deraadt 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/systm.h> 38 #include <sys/proc.h> 39 40 #include <machine/db_machdep.h> /* type definitions */ 41 42 #include <ddb/db_lex.h> 43 #include <ddb/db_access.h> 44 #include <ddb/db_sym.h> 45 #include <ddb/db_break.h> 46 #include <ddb/db_output.h> 47 48 #define NBREAKPOINTS 100 49 struct db_breakpoint db_break_table[NBREAKPOINTS]; 50 db_breakpoint_t db_next_free_breakpoint = &db_break_table[0]; 51 db_breakpoint_t db_free_breakpoints = 0; 52 db_breakpoint_t db_breakpoint_list = 0; 53 54 db_breakpoint_t 55 db_breakpoint_alloc(void) 56 { 57 db_breakpoint_t bkpt; 58 59 if ((bkpt = db_free_breakpoints) != 0) { 60 db_free_breakpoints = bkpt->link; 61 return (bkpt); 62 } 63 if (db_next_free_breakpoint == &db_break_table[NBREAKPOINTS]) { 64 db_printf("All breakpoints used.\n"); 65 return (0); 66 } 67 bkpt = db_next_free_breakpoint; 68 db_next_free_breakpoint++; 69 70 return (bkpt); 71 } 72 73 void 74 db_breakpoint_free(db_breakpoint_t bkpt) 75 { 76 bkpt->link = db_free_breakpoints; 77 db_free_breakpoints = bkpt; 78 } 79 80 void 81 db_set_breakpoint(db_addr_t addr, int count) 82 { 83 db_breakpoint_t bkpt; 84 85 if (db_find_breakpoint(addr)) { 86 db_printf("Already set.\n"); 87 return; 88 } 89 90 #ifdef DB_VALID_BREAKPOINT 91 if (!DB_VALID_BREAKPOINT(addr)) { 92 db_printf("Not a valid address for a breakpoint.\n"); 93 return; 94 } 95 #endif 96 97 bkpt = db_breakpoint_alloc(); 98 if (bkpt == 0) { 99 db_printf("Too many breakpoints.\n"); 100 return; 101 } 102 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 112 void 113 db_delete_breakpoint(db_addr_t addr) 114 { 115 db_breakpoint_t bkpt; 116 db_breakpoint_t *prev; 117 118 for (prev = &db_breakpoint_list; (bkpt = *prev) != 0; 119 prev = &bkpt->link) { 120 if (bkpt->address == addr) { 121 *prev = bkpt->link; 122 break; 123 } 124 } 125 if (bkpt == 0) { 126 db_printf("Not set.\n"); 127 return; 128 } 129 130 db_breakpoint_free(bkpt); 131 } 132 133 db_breakpoint_t 134 db_find_breakpoint(db_addr_t addr) 135 { 136 db_breakpoint_t bkpt; 137 138 for (bkpt = db_breakpoint_list; bkpt != 0; bkpt = bkpt->link) 139 if (bkpt->address == addr) 140 return (bkpt); 141 142 return (0); 143 } 144 145 boolean_t db_breakpoints_inserted = TRUE; 146 147 void 148 db_set_breakpoints(void) 149 { 150 db_breakpoint_t bkpt; 151 152 if (!db_breakpoints_inserted) { 153 for (bkpt = db_breakpoint_list; bkpt != 0; bkpt = bkpt->link) { 154 bkpt->bkpt_inst = 155 db_get_value(bkpt->address, BKPT_SIZE, FALSE); 156 db_put_value(bkpt->address, BKPT_SIZE, 157 BKPT_SET(bkpt->bkpt_inst)); 158 } 159 db_breakpoints_inserted = TRUE; 160 } 161 } 162 163 void 164 db_clear_breakpoints(void) 165 { 166 db_breakpoint_t bkpt; 167 168 if (db_breakpoints_inserted) { 169 for (bkpt = db_breakpoint_list; bkpt != 0; bkpt = bkpt->link) 170 db_put_value(bkpt->address, BKPT_SIZE, bkpt->bkpt_inst); 171 db_breakpoints_inserted = FALSE; 172 } 173 } 174 175 /* 176 * Set a temporary breakpoint. 177 * The instruction is changed immediately, 178 * so the breakpoint does not have to be on the breakpoint list. 179 */ 180 db_breakpoint_t 181 db_set_temp_breakpoint(db_addr_t addr) 182 { 183 db_breakpoint_t bkpt; 184 185 #ifdef DB_VALID_BREAKPOINT 186 if (!DB_VALID_BREAKPOINT(addr)) { 187 db_printf("Not a valid address for a breakpoint.\n"); 188 return (0); 189 } 190 #endif 191 192 bkpt = db_breakpoint_alloc(); 193 if (bkpt == 0) { 194 db_printf("Too many breakpoints.\n"); 195 return (0); 196 } 197 198 bkpt->address = addr; 199 bkpt->flags = BKPT_TEMP; 200 bkpt->init_count = 1; 201 bkpt->count = 1; 202 203 bkpt->bkpt_inst = db_get_value(bkpt->address, BKPT_SIZE, FALSE); 204 db_put_value(bkpt->address, BKPT_SIZE, BKPT_SET(bkpt->bkpt_inst)); 205 return bkpt; 206 } 207 208 void 209 db_delete_temp_breakpoint(db_breakpoint_t bkpt) 210 { 211 db_put_value(bkpt->address, BKPT_SIZE, bkpt->bkpt_inst); 212 db_breakpoint_free(bkpt); 213 } 214 215 /* 216 * List breakpoints. 217 */ 218 void 219 db_list_breakpoints(void) 220 { 221 db_breakpoint_t bkpt; 222 223 if (db_breakpoint_list == NULL) { 224 db_printf("No breakpoints set\n"); 225 return; 226 } 227 228 db_printf(" Count Address\n"); 229 for (bkpt = db_breakpoint_list; bkpt != 0; bkpt = bkpt->link) { 230 db_printf(" %5d ", bkpt->init_count); 231 db_printsym(bkpt->address, DB_STGY_PROC, db_printf); 232 db_printf("\n"); 233 } 234 } 235 236 /* Delete breakpoint */ 237 /*ARGSUSED*/ 238 void 239 db_delete_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif) 240 { 241 db_delete_breakpoint((db_addr_t)addr); 242 } 243 244 /* Set breakpoint with skip count */ 245 /*ARGSUSED*/ 246 void 247 db_breakpoint_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif) 248 { 249 if (count == -1) 250 count = 1; 251 252 db_set_breakpoint((db_addr_t)addr, count); 253 } 254 255 /* list breakpoints */ 256 /*ARGSUSED*/ 257 void 258 db_listbreak_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif) 259 { 260 db_list_breakpoints(); 261 } 262