1 1.26 thorpej /* $NetBSD: db_break.c,v 1.26 2007/02/22 06:41:00 thorpej Exp $ */ 2 1.4 cgd 3 1.17 simonb /* 4 1.1 cgd * Mach Operating System 5 1.1 cgd * Copyright (c) 1991,1990 Carnegie Mellon University 6 1.1 cgd * All Rights Reserved. 7 1.17 simonb * 8 1.1 cgd * Permission to use, copy, modify and distribute this software and its 9 1.1 cgd * documentation is hereby granted, provided that both the copyright 10 1.1 cgd * notice and this permission notice appear in all copies of the 11 1.1 cgd * software, derivative works or modified versions, and any portions 12 1.1 cgd * thereof, and that both notices appear in supporting documentation. 13 1.17 simonb * 14 1.11 pk * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 15 1.1 cgd * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR 16 1.1 cgd * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 17 1.17 simonb * 18 1.1 cgd * Carnegie Mellon requests users of this software to return to 19 1.17 simonb * 20 1.1 cgd * Software Distribution Coordinator or Software.Distribution (at) CS.CMU.EDU 21 1.1 cgd * School of Computer Science 22 1.1 cgd * Carnegie Mellon University 23 1.1 cgd * Pittsburgh PA 15213-3890 24 1.17 simonb * 25 1.1 cgd * any improvements or extensions that they make and grant Carnegie the 26 1.1 cgd * rights to redistribute these changes. 27 1.2 cgd * 28 1.1 cgd * Author: David B. Golub, Carnegie Mellon University 29 1.1 cgd * Date: 7/90 30 1.1 cgd */ 31 1.3 mycroft 32 1.1 cgd /* 33 1.1 cgd * Breakpoints. 34 1.1 cgd */ 35 1.16 lukem 36 1.16 lukem #include <sys/cdefs.h> 37 1.26 thorpej __KERNEL_RCSID(0, "$NetBSD: db_break.c,v 1.26 2007/02/22 06:41:00 thorpej Exp $"); 38 1.16 lukem 39 1.3 mycroft #include <sys/param.h> 40 1.3 mycroft #include <sys/proc.h> 41 1.3 mycroft 42 1.1 cgd #include <machine/db_machdep.h> /* type definitions */ 43 1.1 cgd 44 1.1 cgd #include <ddb/db_lex.h> 45 1.1 cgd #include <ddb/db_access.h> 46 1.1 cgd #include <ddb/db_sym.h> 47 1.1 cgd #include <ddb/db_break.h> 48 1.6 christos #include <ddb/db_output.h> 49 1.1 cgd 50 1.1 cgd #define NBREAKPOINTS 100 51 1.17 simonb static struct db_breakpoint db_break_table[NBREAKPOINTS]; 52 1.17 simonb static db_breakpoint_t db_next_free_breakpoint = &db_break_table[0]; 53 1.17 simonb static db_breakpoint_t db_free_breakpoints = 0; 54 1.17 simonb static db_breakpoint_t db_breakpoint_list = 0; 55 1.17 simonb 56 1.17 simonb static db_breakpoint_t db_breakpoint_alloc(void); 57 1.17 simonb static void db_breakpoint_free(db_breakpoint_t); 58 1.17 simonb static void db_delete_breakpoint(struct vm_map *, db_addr_t); 59 1.17 simonb static db_breakpoint_t db_find_breakpoint(struct vm_map *, db_addr_t); 60 1.17 simonb static void db_list_breakpoints(void); 61 1.17 simonb static void db_set_breakpoint(struct vm_map *, db_addr_t, int); 62 1.1 cgd 63 1.17 simonb static db_breakpoint_t 64 1.17 simonb db_breakpoint_alloc(void) 65 1.1 cgd { 66 1.12 augustss db_breakpoint_t bkpt; 67 1.1 cgd 68 1.1 cgd if ((bkpt = db_free_breakpoints) != 0) { 69 1.17 simonb db_free_breakpoints = bkpt->link; 70 1.17 simonb return (bkpt); 71 1.1 cgd } 72 1.1 cgd if (db_next_free_breakpoint == &db_break_table[NBREAKPOINTS]) { 73 1.17 simonb db_printf("All breakpoints used.\n"); 74 1.17 simonb return (0); 75 1.1 cgd } 76 1.1 cgd bkpt = db_next_free_breakpoint; 77 1.1 cgd db_next_free_breakpoint++; 78 1.1 cgd 79 1.1 cgd return (bkpt); 80 1.1 cgd } 81 1.1 cgd 82 1.17 simonb static void 83 1.17 simonb db_breakpoint_free(db_breakpoint_t bkpt) 84 1.1 cgd { 85 1.1 cgd bkpt->link = db_free_breakpoints; 86 1.1 cgd db_free_breakpoints = bkpt; 87 1.1 cgd } 88 1.1 cgd 89 1.1 cgd void 90 1.17 simonb db_set_breakpoint(struct vm_map *map, db_addr_t addr, int count) 91 1.1 cgd { 92 1.12 augustss db_breakpoint_t bkpt; 93 1.1 cgd 94 1.1 cgd if (db_find_breakpoint(map, addr)) { 95 1.17 simonb db_printf("Already set.\n"); 96 1.17 simonb return; 97 1.1 cgd } 98 1.1 cgd 99 1.1 cgd bkpt = db_breakpoint_alloc(); 100 1.1 cgd if (bkpt == 0) { 101 1.17 simonb db_printf("Too many breakpoints.\n"); 102 1.17 simonb return; 103 1.1 cgd } 104 1.1 cgd 105 1.1 cgd bkpt->map = map; 106 1.18 scw bkpt->address = BKPT_ADDR(addr); 107 1.1 cgd bkpt->flags = 0; 108 1.1 cgd bkpt->init_count = count; 109 1.1 cgd bkpt->count = count; 110 1.1 cgd 111 1.1 cgd bkpt->link = db_breakpoint_list; 112 1.1 cgd db_breakpoint_list = bkpt; 113 1.1 cgd } 114 1.1 cgd 115 1.17 simonb static void 116 1.17 simonb db_delete_breakpoint(struct vm_map *map, db_addr_t addr) 117 1.1 cgd { 118 1.12 augustss db_breakpoint_t bkpt; 119 1.12 augustss db_breakpoint_t *prev; 120 1.1 cgd 121 1.1 cgd for (prev = &db_breakpoint_list; 122 1.1 cgd (bkpt = *prev) != 0; 123 1.1 cgd prev = &bkpt->link) { 124 1.17 simonb if (db_map_equal(bkpt->map, map) && 125 1.18 scw (bkpt->address == BKPT_ADDR(addr))) { 126 1.17 simonb *prev = bkpt->link; 127 1.17 simonb break; 128 1.17 simonb } 129 1.1 cgd } 130 1.1 cgd if (bkpt == 0) { 131 1.17 simonb db_printf("Not set.\n"); 132 1.17 simonb return; 133 1.1 cgd } 134 1.1 cgd 135 1.1 cgd db_breakpoint_free(bkpt); 136 1.1 cgd } 137 1.1 cgd 138 1.1 cgd db_breakpoint_t 139 1.17 simonb db_find_breakpoint(struct vm_map *map, db_addr_t addr) 140 1.1 cgd { 141 1.12 augustss db_breakpoint_t bkpt; 142 1.1 cgd 143 1.1 cgd for (bkpt = db_breakpoint_list; 144 1.1 cgd bkpt != 0; 145 1.1 cgd bkpt = bkpt->link) 146 1.17 simonb if (db_map_equal(bkpt->map, map) && 147 1.18 scw (bkpt->address == BKPT_ADDR(addr))) 148 1.17 simonb return (bkpt); 149 1.17 simonb 150 1.1 cgd return (0); 151 1.1 cgd } 152 1.1 cgd 153 1.1 cgd db_breakpoint_t 154 1.17 simonb db_find_breakpoint_here(db_addr_t addr) 155 1.1 cgd { 156 1.17 simonb return db_find_breakpoint(db_map_addr(addr), addr); 157 1.1 cgd } 158 1.1 cgd 159 1.26 thorpej static bool db_breakpoints_inserted = true; 160 1.1 cgd 161 1.1 cgd void 162 1.17 simonb db_set_breakpoints(void) 163 1.1 cgd { 164 1.12 augustss db_breakpoint_t bkpt; 165 1.1 cgd 166 1.1 cgd if (!db_breakpoints_inserted) { 167 1.1 cgd 168 1.17 simonb for (bkpt = db_breakpoint_list; 169 1.17 simonb bkpt != 0; 170 1.17 simonb bkpt = bkpt->link) 171 1.17 simonb if (db_map_current(bkpt->map)) { 172 1.17 simonb bkpt->bkpt_inst = db_get_value(bkpt->address, 173 1.26 thorpej BKPT_SIZE, false); 174 1.17 simonb db_put_value(bkpt->address, 175 1.21 he BKPT_SIZE, 176 1.21 he BKPT_SET(bkpt->bkpt_inst, bkpt->address)); 177 1.17 simonb } 178 1.26 thorpej db_breakpoints_inserted = true; 179 1.1 cgd } 180 1.1 cgd } 181 1.1 cgd 182 1.1 cgd void 183 1.17 simonb db_clear_breakpoints(void) 184 1.1 cgd { 185 1.12 augustss db_breakpoint_t bkpt; 186 1.1 cgd 187 1.1 cgd if (db_breakpoints_inserted) { 188 1.1 cgd 189 1.17 simonb for (bkpt = db_breakpoint_list; 190 1.17 simonb bkpt != 0; 191 1.17 simonb bkpt = bkpt->link) 192 1.17 simonb if (db_map_current(bkpt->map)) 193 1.17 simonb db_put_value(bkpt->address, BKPT_SIZE, 194 1.17 simonb bkpt->bkpt_inst); 195 1.26 thorpej db_breakpoints_inserted = false; 196 1.1 cgd } 197 1.1 cgd } 198 1.1 cgd 199 1.1 cgd /* 200 1.1 cgd * List breakpoints. 201 1.1 cgd */ 202 1.1 cgd void 203 1.17 simonb db_list_breakpoints(void) 204 1.1 cgd { 205 1.12 augustss db_breakpoint_t bkpt; 206 1.1 cgd 207 1.1 cgd if (db_breakpoint_list == 0) { 208 1.17 simonb db_printf("No breakpoints set\n"); 209 1.17 simonb return; 210 1.1 cgd } 211 1.1 cgd 212 1.1 cgd db_printf(" Map Count Address\n"); 213 1.1 cgd for (bkpt = db_breakpoint_list; 214 1.1 cgd bkpt != 0; 215 1.17 simonb bkpt = bkpt->link) { 216 1.17 simonb db_printf("%s%p %5d ", 217 1.17 simonb db_map_current(bkpt->map) ? "*" : " ", 218 1.17 simonb bkpt->map, bkpt->init_count); 219 1.17 simonb db_printsym(bkpt->address, DB_STGY_PROC, db_printf); 220 1.17 simonb db_printf("\n"); 221 1.1 cgd } 222 1.1 cgd } 223 1.1 cgd 224 1.1 cgd /* Delete breakpoint */ 225 1.1 cgd /*ARGSUSED*/ 226 1.1 cgd void 227 1.25 matt db_delete_cmd(db_expr_t addr, bool have_addr, db_expr_t count, 228 1.23 christos const char *modif) 229 1.1 cgd { 230 1.17 simonb 231 1.1 cgd db_delete_breakpoint(db_map_addr(addr), (db_addr_t)addr); 232 1.1 cgd } 233 1.1 cgd 234 1.1 cgd /* Set breakpoint with skip count */ 235 1.1 cgd /*ARGSUSED*/ 236 1.1 cgd void 237 1.25 matt db_breakpoint_cmd(db_expr_t addr, bool have_addr, db_expr_t count, 238 1.23 christos const char *modif) 239 1.1 cgd { 240 1.17 simonb 241 1.1 cgd if (count == -1) 242 1.17 simonb count = 1; 243 1.1 cgd 244 1.1 cgd db_set_breakpoint(db_map_addr(addr), (db_addr_t)addr, count); 245 1.1 cgd } 246 1.1 cgd 247 1.1 cgd /* list breakpoints */ 248 1.6 christos /*ARGSUSED*/ 249 1.1 cgd void 250 1.25 matt db_listbreak_cmd(db_expr_t addr, bool have_addr, 251 1.23 christos db_expr_t count, const char *modif) 252 1.1 cgd { 253 1.17 simonb 254 1.1 cgd db_list_breakpoints(); 255 1.1 cgd } 256 1.1 cgd 257 1.14 mrg #include <uvm/uvm_extern.h> 258 1.1 cgd 259 1.1 cgd /* 260 1.1 cgd * We want ddb to be usable before most of the kernel has been 261 1.1 cgd * initialized. In particular, current_thread() or kernel_map 262 1.1 cgd * (or both) may be null. 263 1.1 cgd */ 264 1.1 cgd 265 1.24 thorpej bool 266 1.17 simonb db_map_equal(struct vm_map *map1, struct vm_map *map2) 267 1.1 cgd { 268 1.17 simonb 269 1.1 cgd return ((map1 == map2) || 270 1.1 cgd ((map1 == NULL) && (map2 == kernel_map)) || 271 1.1 cgd ((map1 == kernel_map) && (map2 == NULL))); 272 1.1 cgd } 273 1.1 cgd 274 1.24 thorpej bool 275 1.23 christos db_map_current(struct vm_map *map) 276 1.1 cgd { 277 1.1 cgd #if 0 278 1.1 cgd thread_t thread; 279 1.1 cgd 280 1.1 cgd return ((map == NULL) || 281 1.1 cgd (map == kernel_map) || 282 1.1 cgd (((thread = current_thread()) != NULL) && 283 1.1 cgd (map == thread->task->map))); 284 1.1 cgd #else 285 1.17 simonb 286 1.1 cgd return (1); 287 1.1 cgd #endif 288 1.1 cgd } 289 1.1 cgd 290 1.15 chs struct vm_map * 291 1.23 christos db_map_addr(vaddr_t addr) 292 1.1 cgd { 293 1.1 cgd #if 0 294 1.1 cgd thread_t thread; 295 1.1 cgd 296 1.1 cgd /* 297 1.1 cgd * We want to return kernel_map for all 298 1.1 cgd * non-user addresses, even when debugging 299 1.1 cgd * kernel tasks with their own maps. 300 1.1 cgd */ 301 1.1 cgd 302 1.17 simonb if ((VM_MIN_ADDRESS <= addr) && (addr < VM_MAX_ADDRESS) && 303 1.1 cgd ((thread = current_thread()) != NULL)) 304 1.17 simonb return thread->task->map; 305 1.1 cgd else 306 1.1 cgd #endif 307 1.17 simonb return kernel_map; 308 1.1 cgd } 309