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