Home | History | Annotate | Line # | Download | only in ddb
      1 /*	$NetBSD: db_watch.c,v 1.27 2007/02/22 06:41:01 thorpej 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 "AS IS"
     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/cdefs.h>
     33 __KERNEL_RCSID(0, "$NetBSD: db_watch.c,v 1.27 2007/02/22 06:41:01 thorpej Exp $");
     34 
     35 #include <sys/param.h>
     36 #include <sys/proc.h>
     37 
     38 #include <machine/db_machdep.h>
     39 
     40 #include <ddb/db_break.h>
     41 #include <ddb/db_watch.h>
     42 #include <ddb/db_lex.h>
     43 #include <ddb/db_access.h>
     44 #include <ddb/db_run.h>
     45 #include <ddb/db_sym.h>
     46 #include <ddb/db_output.h>
     47 #include <ddb/db_command.h>
     48 #include <ddb/db_extern.h>
     49 
     50 /*
     51  * Watchpoints.
     52  */
     53 
     54 static bool			db_watchpoints_inserted = true;
     55 
     56 #define	NWATCHPOINTS	100
     57 static struct db_watchpoint	db_watch_table[NWATCHPOINTS];
     58 static db_watchpoint_t		db_next_free_watchpoint = &db_watch_table[0];
     59 static db_watchpoint_t		db_free_watchpoints = 0;
     60 static db_watchpoint_t		db_watchpoint_list = 0;
     61 
     62 static void		db_delete_watchpoint(struct vm_map *, db_addr_t);
     63 static void		db_list_watchpoints(void);
     64 static void		db_set_watchpoint(struct vm_map *, db_addr_t, vsize_t);
     65 static db_watchpoint_t	db_watchpoint_alloc(void);
     66 static void		db_watchpoint_free(db_watchpoint_t);
     67 
     68 db_watchpoint_t
     69 db_watchpoint_alloc(void)
     70 {
     71 	db_watchpoint_t	watch;
     72 
     73 	if ((watch = db_free_watchpoints) != 0) {
     74 		db_free_watchpoints = watch->link;
     75 		return (watch);
     76 	}
     77 	if (db_next_free_watchpoint == &db_watch_table[NWATCHPOINTS]) {
     78 		db_printf("All watchpoints used.\n");
     79 		return (0);
     80 	}
     81 	watch = db_next_free_watchpoint;
     82 	db_next_free_watchpoint++;
     83 
     84 	return (watch);
     85 }
     86 
     87 void
     88 db_watchpoint_free(db_watchpoint_t watch)
     89 {
     90 	watch->link = db_free_watchpoints;
     91 	db_free_watchpoints = watch;
     92 }
     93 
     94 void
     95 db_set_watchpoint(struct vm_map *map, db_addr_t addr, vsize_t size)
     96 {
     97 	db_watchpoint_t	watch;
     98 
     99 	if (map == NULL) {
    100 		db_printf("No map.\n");
    101 		return;
    102 	}
    103 
    104 	/*
    105 	 *	Should we do anything fancy with overlapping regions?
    106 	 */
    107 
    108 	for (watch = db_watchpoint_list; watch != 0; watch = watch->link)
    109 		if (db_map_equal(watch->map, map) &&
    110 		    (watch->loaddr == addr) &&
    111 		    (watch->hiaddr == addr+size)) {
    112 			db_printf("Already set.\n");
    113 			return;
    114 		}
    115 
    116 	watch = db_watchpoint_alloc();
    117 	if (watch == 0) {
    118 		db_printf("Too many watchpoints.\n");
    119 		return;
    120 	}
    121 
    122 	watch->map = map;
    123 	watch->loaddr = addr;
    124 	watch->hiaddr = addr+size;
    125 
    126 	watch->link = db_watchpoint_list;
    127 	db_watchpoint_list = watch;
    128 
    129 	db_watchpoints_inserted = false;
    130 }
    131 
    132 static void
    133 db_delete_watchpoint(struct vm_map *map, db_addr_t addr)
    134 {
    135 	db_watchpoint_t	watch;
    136 	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(void)
    154 {
    155 	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; watch != 0; watch = watch->link)
    164 		db_printf("%s%p  %8lx  %lx\n",
    165 		    db_map_current(watch->map) ? "*" : " ",
    166 		    watch->map, (long)watch->loaddr,
    167 		    (long)(watch->hiaddr - watch->loaddr));
    168 }
    169 
    170 /* Delete watchpoint */
    171 /*ARGSUSED*/
    172 void
    173 db_deletewatch_cmd(db_expr_t addr, bool have_addr,
    174     db_expr_t count, const char *modif)
    175 {
    176 
    177 	db_delete_watchpoint(db_map_addr(addr), addr);
    178 }
    179 
    180 /* Set watchpoint */
    181 /*ARGSUSED*/
    182 void
    183 db_watchpoint_cmd(db_expr_t addr, bool have_addr,
    184     db_expr_t count, const char *modif)
    185 {
    186 	vsize_t size;
    187 	db_expr_t value;
    188 
    189 	if (db_expression(&value))
    190 		size = (vsize_t) value;
    191 	else
    192 		size = 4;
    193 	db_skip_to_eol();
    194 
    195 	db_set_watchpoint(db_map_addr(addr), addr, size);
    196 }
    197 
    198 /* list watchpoints */
    199 /*ARGSUSED*/
    200 void
    201 db_listwatch_cmd(db_expr_t addr, bool have_addr,
    202     db_expr_t count, const char *modif)
    203 {
    204 
    205 	db_list_watchpoints();
    206 }
    207 
    208 void
    209 db_set_watchpoints(void)
    210 {
    211 	db_watchpoint_t	watch;
    212 
    213 	if (!db_watchpoints_inserted) {
    214 		for (watch = db_watchpoint_list;
    215 		     watch != 0;
    216 		     watch = watch->link) {
    217 			pmap_protect(watch->map->pmap,
    218 			    trunc_page(watch->loaddr),
    219 			    round_page(watch->hiaddr),
    220 			    VM_PROT_READ);
    221 			pmap_update(watch->map->pmap);
    222 		}
    223 
    224 		db_watchpoints_inserted = true;
    225 	}
    226 }
    227 
    228 void
    229 db_clear_watchpoints(void)
    230 {
    231 
    232 	db_watchpoints_inserted = false;
    233 }
    234