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