Home | History | Annotate | Line # | Download | only in ddb
db_watch.c revision 1.7
      1 /*	$NetBSD: db_watch.c,v 1.7 1994/10/09 08:30:15 mycroft Exp $	*/
      2 
      3 /*
      4  * Mach Operating System
      5  * Copyright (c) 1991,1990 Carnegie Mellon University
      6  * All Rights Reserved.
      7  *
      8  * Permission to use, copy, modify and distribute this software and its
      9  * documentation is hereby granted, provided that both the copyright
     10  * notice and this permission notice appear in all copies of the
     11  * software, derivative works or modified versions, and any portions
     12  * thereof, and that both notices appear in supporting documentation.
     13  *
     14  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
     15  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
     16  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
     17  *
     18  * Carnegie Mellon requests users of this software to return to
     19  *
     20  *  Software Distribution Coordinator  or  Software.Distribution (at) CS.CMU.EDU
     21  *  School of Computer Science
     22  *  Carnegie Mellon University
     23  *  Pittsburgh PA 15213-3890
     24  *
     25  * any improvements or extensions that they make and grant Carnegie the
     26  * rights to redistribute these changes.
     27  *
     28  * 	Author: Richard P. Draves, Carnegie Mellon University
     29  *	Date:	10/90
     30  */
     31 
     32 #include <sys/param.h>
     33 #include <sys/proc.h>
     34 
     35 #include <machine/db_machdep.h>
     36 
     37 #include <ddb/db_break.h>
     38 #include <ddb/db_watch.h>
     39 #include <ddb/db_lex.h>
     40 #include <ddb/db_access.h>
     41 #include <ddb/db_sym.h>
     42 
     43 /*
     44  * Watchpoints.
     45  */
     46 
     47 boolean_t	db_watchpoints_inserted = TRUE;
     48 
     49 #define	NWATCHPOINTS	100
     50 struct db_watchpoint	db_watch_table[NWATCHPOINTS];
     51 db_watchpoint_t		db_next_free_watchpoint = &db_watch_table[0];
     52 db_watchpoint_t		db_free_watchpoints = 0;
     53 db_watchpoint_t		db_watchpoint_list = 0;
     54 
     55 db_watchpoint_t
     56 db_watchpoint_alloc()
     57 {
     58 	register db_watchpoint_t	watch;
     59 
     60 	if ((watch = db_free_watchpoints) != 0) {
     61 	    db_free_watchpoints = watch->link;
     62 	    return (watch);
     63 	}
     64 	if (db_next_free_watchpoint == &db_watch_table[NWATCHPOINTS]) {
     65 	    db_printf("All watchpoints used.\n");
     66 	    return (0);
     67 	}
     68 	watch = db_next_free_watchpoint;
     69 	db_next_free_watchpoint++;
     70 
     71 	return (watch);
     72 }
     73 
     74 void
     75 db_watchpoint_free(watch)
     76 	register db_watchpoint_t	watch;
     77 {
     78 	watch->link = db_free_watchpoints;
     79 	db_free_watchpoints = watch;
     80 }
     81 
     82 void
     83 db_set_watchpoint(map, addr, size)
     84 	vm_map_t	map;
     85 	db_addr_t	addr;
     86 	vm_size_t	size;
     87 {
     88 	register db_watchpoint_t	watch;
     89 
     90 	if (map == NULL) {
     91 	    db_printf("No map.\n");
     92 	    return;
     93 	}
     94 
     95 	/*
     96 	 *	Should we do anything fancy with overlapping regions?
     97 	 */
     98 
     99 	for (watch = db_watchpoint_list;
    100 	     watch != 0;
    101 	     watch = watch->link)
    102 	    if (db_map_equal(watch->map, map) &&
    103 		(watch->loaddr == addr) &&
    104 		(watch->hiaddr == addr+size)) {
    105 		db_printf("Already set.\n");
    106 		return;
    107 	    }
    108 
    109 	watch = db_watchpoint_alloc();
    110 	if (watch == 0) {
    111 	    db_printf("Too many watchpoints.\n");
    112 	    return;
    113 	}
    114 
    115 	watch->map = map;
    116 	watch->loaddr = addr;
    117 	watch->hiaddr = addr+size;
    118 
    119 	watch->link = db_watchpoint_list;
    120 	db_watchpoint_list = watch;
    121 
    122 	db_watchpoints_inserted = FALSE;
    123 }
    124 
    125 void
    126 db_delete_watchpoint(map, addr)
    127 	vm_map_t	map;
    128 	db_addr_t	addr;
    129 {
    130 	register db_watchpoint_t	watch;
    131 	register db_watchpoint_t	*prev;
    132 
    133 	for (prev = &db_watchpoint_list;
    134 	     (watch = *prev) != 0;
    135 	     prev = &watch->link)
    136 	    if (db_map_equal(watch->map, map) &&
    137 		(watch->loaddr <= addr) &&
    138 		(addr < watch->hiaddr)) {
    139 		*prev = watch->link;
    140 		db_watchpoint_free(watch);
    141 		return;
    142 	    }
    143 
    144 	db_printf("Not set.\n");
    145 }
    146 
    147 void
    148 db_list_watchpoints()
    149 {
    150 	register db_watchpoint_t	watch;
    151 
    152 	if (db_watchpoint_list == 0) {
    153 	    db_printf("No watchpoints set\n");
    154 	    return;
    155 	}
    156 
    157 	db_printf(" Map        Address  Size\n");
    158 	for (watch = db_watchpoint_list;
    159 	     watch != 0;
    160 	     watch = watch->link)
    161 	    db_printf("%s%8x  %8x  %x\n",
    162 		      db_map_current(watch->map) ? "*" : " ",
    163 		      watch->map, watch->loaddr,
    164 		      watch->hiaddr - watch->loaddr);
    165 }
    166 
    167 /* Delete watchpoint */
    168 /*ARGSUSED*/
    169 void
    170 db_deletewatch_cmd(addr, have_addr, count, modif)
    171 	db_expr_t	addr;
    172 	int		have_addr;
    173 	db_expr_t	count;
    174 	char *		modif;
    175 {
    176 	db_delete_watchpoint(db_map_addr(addr), addr);
    177 }
    178 
    179 /* Set watchpoint */
    180 /*ARGSUSED*/
    181 void
    182 db_watchpoint_cmd(addr, have_addr, count, modif)
    183 	db_expr_t	addr;
    184 	int		have_addr;
    185 	db_expr_t	count;
    186 	char *		modif;
    187 {
    188 	vm_size_t	size;
    189 	db_expr_t	value;
    190 
    191 	if (db_expression(&value))
    192 	    size = (vm_size_t) value;
    193 	else
    194 	    size = 4;
    195 	db_skip_to_eol();
    196 
    197 	db_set_watchpoint(db_map_addr(addr), addr, size);
    198 }
    199 
    200 /* list watchpoints */
    201 void
    202 db_listwatch_cmd()
    203 {
    204 	db_list_watchpoints();
    205 }
    206 
    207 void
    208 db_set_watchpoints()
    209 {
    210 	register db_watchpoint_t	watch;
    211 
    212 	if (!db_watchpoints_inserted) {
    213 	    for (watch = db_watchpoint_list;
    214 	         watch != 0;
    215 	         watch = watch->link)
    216 		pmap_protect(watch->map->pmap,
    217 			     trunc_page(watch->loaddr),
    218 			     round_page(watch->hiaddr),
    219 			     VM_PROT_READ);
    220 
    221 	    db_watchpoints_inserted = TRUE;
    222 	}
    223 }
    224 
    225 void
    226 db_clear_watchpoints()
    227 {
    228 	db_watchpoints_inserted = FALSE;
    229 }
    230 
    231 boolean_t
    232 db_find_watchpoint(map, addr, regs)
    233 	vm_map_t	map;
    234 	db_addr_t	addr;
    235 	db_regs_t	*regs;
    236 {
    237 	register db_watchpoint_t watch;
    238 	db_watchpoint_t found = 0;
    239 
    240 	for (watch = db_watchpoint_list;
    241 	     watch != 0;
    242 	     watch = watch->link)
    243 	    if (db_map_equal(watch->map, map)) {
    244 		if ((watch->loaddr <= addr) &&
    245 		    (addr < watch->hiaddr))
    246 		    return (TRUE);
    247 		else if ((trunc_page(watch->loaddr) <= addr) &&
    248 			 (addr < round_page(watch->hiaddr)))
    249 		    found = watch;
    250 	    }
    251 
    252 	/*
    253 	 *	We didn't hit exactly on a watchpoint, but we are
    254 	 *	in a protected region.  We want to single-step
    255 	 *	and then re-protect.
    256 	 */
    257 
    258 	if (found) {
    259 	    db_watchpoints_inserted = FALSE;
    260 	    db_single_step(regs);
    261 	}
    262 
    263 	return (FALSE);
    264 }
    265