Home | History | Annotate | Line # | Download | only in ddb
db_watch.c revision 1.6
      1 /*	$NetBSD: db_watch.c,v 1.6 1994/10/09 08:19:43 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 <ddb/db_watch.h>
     36 #include <ddb/db_lex.h>
     37 #include <ddb/db_access.h>
     38 #include <ddb/db_sym.h>
     39 
     40 /*
     41  * Watchpoints.
     42  */
     43 
     44 boolean_t	db_watchpoints_inserted = TRUE;
     45 
     46 #define	NWATCHPOINTS	100
     47 struct db_watchpoint	db_watch_table[NWATCHPOINTS];
     48 db_watchpoint_t		db_next_free_watchpoint = &db_watch_table[0];
     49 db_watchpoint_t		db_free_watchpoints = 0;
     50 db_watchpoint_t		db_watchpoint_list = 0;
     51 
     52 db_watchpoint_t
     53 db_watchpoint_alloc()
     54 {
     55 	register db_watchpoint_t	watch;
     56 
     57 	if ((watch = db_free_watchpoints) != 0) {
     58 	    db_free_watchpoints = watch->link;
     59 	    return (watch);
     60 	}
     61 	if (db_next_free_watchpoint == &db_watch_table[NWATCHPOINTS]) {
     62 	    db_printf("All watchpoints used.\n");
     63 	    return (0);
     64 	}
     65 	watch = db_next_free_watchpoint;
     66 	db_next_free_watchpoint++;
     67 
     68 	return (watch);
     69 }
     70 
     71 void
     72 db_watchpoint_free(watch)
     73 	register db_watchpoint_t	watch;
     74 {
     75 	watch->link = db_free_watchpoints;
     76 	db_free_watchpoints = watch;
     77 }
     78 
     79 void
     80 db_set_watchpoint(map, addr, size)
     81 	vm_map_t	map;
     82 	db_addr_t	addr;
     83 	vm_size_t	size;
     84 {
     85 	register db_watchpoint_t	watch;
     86 
     87 	if (map == NULL) {
     88 	    db_printf("No map.\n");
     89 	    return;
     90 	}
     91 
     92 	/*
     93 	 *	Should we do anything fancy with overlapping regions?
     94 	 */
     95 
     96 	for (watch = db_watchpoint_list;
     97 	     watch != 0;
     98 	     watch = watch->link)
     99 	    if (db_map_equal(watch->map, map) &&
    100 		(watch->loaddr == addr) &&
    101 		(watch->hiaddr == addr+size)) {
    102 		db_printf("Already set.\n");
    103 		return;
    104 	    }
    105 
    106 	watch = db_watchpoint_alloc();
    107 	if (watch == 0) {
    108 	    db_printf("Too many watchpoints.\n");
    109 	    return;
    110 	}
    111 
    112 	watch->map = map;
    113 	watch->loaddr = addr;
    114 	watch->hiaddr = addr+size;
    115 
    116 	watch->link = db_watchpoint_list;
    117 	db_watchpoint_list = watch;
    118 
    119 	db_watchpoints_inserted = FALSE;
    120 }
    121 
    122 void
    123 db_delete_watchpoint(map, addr)
    124 	vm_map_t	map;
    125 	db_addr_t	addr;
    126 {
    127 	register db_watchpoint_t	watch;
    128 	register db_watchpoint_t	*prev;
    129 
    130 	for (prev = &db_watchpoint_list;
    131 	     (watch = *prev) != 0;
    132 	     prev = &watch->link)
    133 	    if (db_map_equal(watch->map, map) &&
    134 		(watch->loaddr <= addr) &&
    135 		(addr < watch->hiaddr)) {
    136 		*prev = watch->link;
    137 		db_watchpoint_free(watch);
    138 		return;
    139 	    }
    140 
    141 	db_printf("Not set.\n");
    142 }
    143 
    144 void
    145 db_list_watchpoints()
    146 {
    147 	register db_watchpoint_t	watch;
    148 
    149 	if (db_watchpoint_list == 0) {
    150 	    db_printf("No watchpoints set\n");
    151 	    return;
    152 	}
    153 
    154 	db_printf(" Map        Address  Size\n");
    155 	for (watch = db_watchpoint_list;
    156 	     watch != 0;
    157 	     watch = watch->link)
    158 	    db_printf("%s%8x  %8x  %x\n",
    159 		      db_map_current(watch->map) ? "*" : " ",
    160 		      watch->map, watch->loaddr,
    161 		      watch->hiaddr - watch->loaddr);
    162 }
    163 
    164 /* Delete watchpoint */
    165 /*ARGSUSED*/
    166 void
    167 db_deletewatch_cmd(addr, have_addr, count, modif)
    168 	db_expr_t	addr;
    169 	int		have_addr;
    170 	db_expr_t	count;
    171 	char *		modif;
    172 {
    173 	db_delete_watchpoint(db_map_addr(addr), addr);
    174 }
    175 
    176 /* Set watchpoint */
    177 /*ARGSUSED*/
    178 void
    179 db_watchpoint_cmd(addr, have_addr, count, modif)
    180 	db_expr_t	addr;
    181 	int		have_addr;
    182 	db_expr_t	count;
    183 	char *		modif;
    184 {
    185 	vm_size_t	size;
    186 	db_expr_t	value;
    187 
    188 	if (db_expression(&value))
    189 	    size = (vm_size_t) value;
    190 	else
    191 	    size = 4;
    192 	db_skip_to_eol();
    193 
    194 	db_set_watchpoint(db_map_addr(addr), addr, size);
    195 }
    196 
    197 /* list watchpoints */
    198 void
    199 db_listwatch_cmd()
    200 {
    201 	db_list_watchpoints();
    202 }
    203 
    204 void
    205 db_set_watchpoints()
    206 {
    207 	register db_watchpoint_t	watch;
    208 
    209 	if (!db_watchpoints_inserted) {
    210 	    for (watch = db_watchpoint_list;
    211 	         watch != 0;
    212 	         watch = watch->link)
    213 		pmap_protect(watch->map->pmap,
    214 			     trunc_page(watch->loaddr),
    215 			     round_page(watch->hiaddr),
    216 			     VM_PROT_READ);
    217 
    218 	    db_watchpoints_inserted = TRUE;
    219 	}
    220 }
    221 
    222 void
    223 db_clear_watchpoints()
    224 {
    225 	db_watchpoints_inserted = FALSE;
    226 }
    227 
    228 boolean_t
    229 db_find_watchpoint(map, addr, regs)
    230 	vm_map_t	map;
    231 	db_addr_t	addr;
    232 	db_regs_t	*regs;
    233 {
    234 	register db_watchpoint_t watch;
    235 	db_watchpoint_t found = 0;
    236 
    237 	for (watch = db_watchpoint_list;
    238 	     watch != 0;
    239 	     watch = watch->link)
    240 	    if (db_map_equal(watch->map, map)) {
    241 		if ((watch->loaddr <= addr) &&
    242 		    (addr < watch->hiaddr))
    243 		    return (TRUE);
    244 		else if ((trunc_page(watch->loaddr) <= addr) &&
    245 			 (addr < round_page(watch->hiaddr)))
    246 		    found = watch;
    247 	    }
    248 
    249 	/*
    250 	 *	We didn't hit exactly on a watchpoint, but we are
    251 	 *	in a protected region.  We want to single-step
    252 	 *	and then re-protect.
    253 	 */
    254 
    255 	if (found) {
    256 	    db_watchpoints_inserted = FALSE;
    257 	    db_single_step(regs);
    258 	}
    259 
    260 	return (FALSE);
    261 }
    262