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