Annotation of sys/ddb/db_break.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: db_break.c,v 1.13 2006/03/13 06:23:20 jsg 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(struct vm_map *map, db_addr_t addr, int count)
! 83: {
! 84: db_breakpoint_t bkpt;
! 85:
! 86: if (db_find_breakpoint(map, 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->map = map;
! 105: bkpt->address = addr;
! 106: bkpt->flags = 0;
! 107: bkpt->init_count = count;
! 108: bkpt->count = count;
! 109:
! 110: bkpt->link = db_breakpoint_list;
! 111: db_breakpoint_list = bkpt;
! 112: }
! 113:
! 114: void
! 115: db_delete_breakpoint(struct vm_map *map, db_addr_t addr)
! 116: {
! 117: db_breakpoint_t bkpt;
! 118: 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:
! 137: db_breakpoint_t
! 138: db_find_breakpoint(struct vm_map *map, db_addr_t addr)
! 139: {
! 140: db_breakpoint_t bkpt;
! 141:
! 142: for (bkpt = db_breakpoint_list;
! 143: bkpt != 0;
! 144: bkpt = bkpt->link)
! 145: {
! 146: if (db_map_equal(bkpt->map, map) &&
! 147: (bkpt->address == addr))
! 148: return (bkpt);
! 149: }
! 150: return (0);
! 151: }
! 152:
! 153: db_breakpoint_t
! 154: db_find_breakpoint_here(db_addr_t addr)
! 155: {
! 156: return db_find_breakpoint(db_map_addr(addr), addr);
! 157: }
! 158:
! 159: boolean_t db_breakpoints_inserted = TRUE;
! 160:
! 161: void
! 162: db_set_breakpoints(void)
! 163: {
! 164: db_breakpoint_t bkpt;
! 165:
! 166: if (!db_breakpoints_inserted) {
! 167:
! 168: for (bkpt = db_breakpoint_list;
! 169: bkpt != 0;
! 170: bkpt = bkpt->link)
! 171: if (db_map_current(bkpt->map)) {
! 172: bkpt->bkpt_inst = db_get_value(bkpt->address, BKPT_SIZE,
! 173: FALSE);
! 174: db_put_value(bkpt->address, BKPT_SIZE,
! 175: BKPT_SET(bkpt->bkpt_inst));
! 176: }
! 177: db_breakpoints_inserted = TRUE;
! 178: }
! 179: }
! 180:
! 181: void
! 182: db_clear_breakpoints(void)
! 183: {
! 184: db_breakpoint_t bkpt;
! 185:
! 186: if (db_breakpoints_inserted) {
! 187:
! 188: for (bkpt = db_breakpoint_list;
! 189: bkpt != 0;
! 190: bkpt = bkpt->link)
! 191: if (db_map_current(bkpt->map)) {
! 192: db_put_value(bkpt->address, BKPT_SIZE, bkpt->bkpt_inst);
! 193: }
! 194: db_breakpoints_inserted = FALSE;
! 195: }
! 196: }
! 197:
! 198: /*
! 199: * Set a temporary breakpoint.
! 200: * The instruction is changed immediately,
! 201: * so the breakpoint does not have to be on the breakpoint list.
! 202: */
! 203: db_breakpoint_t
! 204: db_set_temp_breakpoint(db_addr_t addr)
! 205: {
! 206: db_breakpoint_t bkpt;
! 207:
! 208: #ifdef DB_VALID_BREAKPOINT
! 209: if (!DB_VALID_BREAKPOINT(addr)) {
! 210: db_printf("Not a valid address for a breakpoint.\n");
! 211: return (0);
! 212: }
! 213: #endif
! 214:
! 215: bkpt = db_breakpoint_alloc();
! 216: if (bkpt == 0) {
! 217: db_printf("Too many breakpoints.\n");
! 218: return (0);
! 219: }
! 220:
! 221: bkpt->map = NULL;
! 222: bkpt->address = addr;
! 223: bkpt->flags = BKPT_TEMP;
! 224: bkpt->init_count = 1;
! 225: bkpt->count = 1;
! 226:
! 227: bkpt->bkpt_inst = db_get_value(bkpt->address, BKPT_SIZE, FALSE);
! 228: db_put_value(bkpt->address, BKPT_SIZE, BKPT_SET(bkpt->bkpt_inst));
! 229: return bkpt;
! 230: }
! 231:
! 232: void
! 233: db_delete_temp_breakpoint(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: */
! 242: void
! 243: db_list_breakpoints(void)
! 244: {
! 245: 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%p %5d ",
! 258: db_map_current(bkpt->map) ? "*" : " ",
! 259: bkpt->map, bkpt->init_count);
! 260: db_printsym(bkpt->address, DB_STGY_PROC, db_printf);
! 261: db_printf("\n");
! 262: }
! 263: }
! 264:
! 265: /* Delete breakpoint */
! 266: /*ARGSUSED*/
! 267: void
! 268: db_delete_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif)
! 269: {
! 270: db_delete_breakpoint(db_map_addr(addr), (db_addr_t)addr);
! 271: }
! 272:
! 273: /* Set breakpoint with skip count */
! 274: /*ARGSUSED*/
! 275: void
! 276: db_breakpoint_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif)
! 277: {
! 278: if (count == -1)
! 279: count = 1;
! 280:
! 281: db_set_breakpoint(db_map_addr(addr), (db_addr_t)addr, count);
! 282: }
! 283:
! 284: /* list breakpoints */
! 285: /*ARGSUSED*/
! 286: void
! 287: db_listbreak_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif)
! 288: {
! 289: db_list_breakpoints();
! 290: }
! 291:
! 292: /*
! 293: * We want ddb to be usable before most of the kernel has been
! 294: * initialized. In particular, current_thread() or kernel_map
! 295: * (or both) may be null.
! 296: */
! 297:
! 298: boolean_t
! 299: db_map_equal(struct vm_map *map1, struct vm_map *map2)
! 300: {
! 301: return ((map1 == map2) ||
! 302: ((map1 == NULL) && (map2 == kernel_map)) ||
! 303: ((map1 == kernel_map) && (map2 == NULL)));
! 304: }
! 305:
! 306: boolean_t
! 307: db_map_current(struct vm_map *map)
! 308: {
! 309: #if 0
! 310: thread_t thread;
! 311:
! 312: return ((map == NULL) ||
! 313: (map == kernel_map) ||
! 314: (((thread = current_thread()) != NULL) &&
! 315: (map == thread->proc->map)));
! 316: #else
! 317: return (1);
! 318: #endif
! 319: }
! 320:
! 321: struct vm_map *
! 322: db_map_addr(vaddr_t addr)
! 323: {
! 324: #if 0
! 325: thread_t thread;
! 326:
! 327: /*
! 328: * We want to return kernel_map for all
! 329: * non-user addresses, even when debugging
! 330: * kernel tasks with their own maps.
! 331: */
! 332:
! 333: if ((VM_MIN_ADDRESS <= addr) &&
! 334: (addr < VM_MAX_ADDRESS) &&
! 335: ((thread = current_thread()) != NULL))
! 336: return thread->proc->map;
! 337: else
! 338: #endif
! 339: return kernel_map;
! 340: }
CVSweb