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