Home | History | Annotate | Line # | Download | only in ddb
db_break.c revision 1.6
      1 /*	$NetBSD: db_break.c,v 1.6 1996/02/05 01:56:50 christos 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: David B. Golub, Carnegie Mellon University
     29  *	Date:	7/90
     30  */
     31 
     32 /*
     33  * Breakpoints.
     34  */
     35 #include <sys/param.h>
     36 #include <sys/proc.h>
     37 
     38 #include <machine/db_machdep.h>		/* type definitions */
     39 
     40 #include <ddb/db_lex.h>
     41 #include <ddb/db_access.h>
     42 #include <ddb/db_sym.h>
     43 #include <ddb/db_break.h>
     44 #include <ddb/db_output.h>
     45 
     46 #define	NBREAKPOINTS	100
     47 struct db_breakpoint	db_break_table[NBREAKPOINTS];
     48 db_breakpoint_t		db_next_free_breakpoint = &db_break_table[0];
     49 db_breakpoint_t		db_free_breakpoints = 0;
     50 db_breakpoint_t		db_breakpoint_list = 0;
     51 
     52 db_breakpoint_t
     53 db_breakpoint_alloc()
     54 {
     55 	register db_breakpoint_t	bkpt;
     56 
     57 	if ((bkpt = db_free_breakpoints) != 0) {
     58 	    db_free_breakpoints = bkpt->link;
     59 	    return (bkpt);
     60 	}
     61 	if (db_next_free_breakpoint == &db_break_table[NBREAKPOINTS]) {
     62 	    db_printf("All breakpoints used.\n");
     63 	    return (0);
     64 	}
     65 	bkpt = db_next_free_breakpoint;
     66 	db_next_free_breakpoint++;
     67 
     68 	return (bkpt);
     69 }
     70 
     71 void
     72 db_breakpoint_free(bkpt)
     73 	register db_breakpoint_t	bkpt;
     74 {
     75 	bkpt->link = db_free_breakpoints;
     76 	db_free_breakpoints = bkpt;
     77 }
     78 
     79 void
     80 db_set_breakpoint(map, addr, count)
     81 	vm_map_t	map;
     82 	db_addr_t	addr;
     83 	int		count;
     84 {
     85 	register db_breakpoint_t	bkpt;
     86 
     87 	if (db_find_breakpoint(map, addr)) {
     88 	    db_printf("Already set.\n");
     89 	    return;
     90 	}
     91 
     92 	bkpt = db_breakpoint_alloc();
     93 	if (bkpt == 0) {
     94 	    db_printf("Too many breakpoints.\n");
     95 	    return;
     96 	}
     97 
     98 	bkpt->map = map;
     99 	bkpt->address = addr;
    100 	bkpt->flags = 0;
    101 	bkpt->init_count = count;
    102 	bkpt->count = count;
    103 
    104 	bkpt->link = db_breakpoint_list;
    105 	db_breakpoint_list = bkpt;
    106 }
    107 
    108 void
    109 db_delete_breakpoint(map, addr)
    110 	vm_map_t	map;
    111 	db_addr_t	addr;
    112 {
    113 	register db_breakpoint_t	bkpt;
    114 	register db_breakpoint_t	*prev;
    115 
    116 	for (prev = &db_breakpoint_list;
    117 	     (bkpt = *prev) != 0;
    118 	     prev = &bkpt->link) {
    119 	    if (db_map_equal(bkpt->map, map) &&
    120 		(bkpt->address == addr)) {
    121 		*prev = bkpt->link;
    122 		break;
    123 	    }
    124 	}
    125 	if (bkpt == 0) {
    126 	    db_printf("Not set.\n");
    127 	    return;
    128 	}
    129 
    130 	db_breakpoint_free(bkpt);
    131 }
    132 
    133 db_breakpoint_t
    134 db_find_breakpoint(map, addr)
    135 	vm_map_t	map;
    136 	db_addr_t	addr;
    137 {
    138 	register db_breakpoint_t	bkpt;
    139 
    140 	for (bkpt = db_breakpoint_list;
    141 	     bkpt != 0;
    142 	     bkpt = bkpt->link)
    143 	{
    144 	    if (db_map_equal(bkpt->map, map) &&
    145 		(bkpt->address == addr))
    146 		return (bkpt);
    147 	}
    148 	return (0);
    149 }
    150 
    151 db_breakpoint_t
    152 db_find_breakpoint_here(addr)
    153 	db_addr_t	addr;
    154 {
    155     return db_find_breakpoint(db_map_addr(addr), addr);
    156 }
    157 
    158 boolean_t	db_breakpoints_inserted = TRUE;
    159 
    160 void
    161 db_set_breakpoints()
    162 {
    163 	register db_breakpoint_t	bkpt;
    164 
    165 	if (!db_breakpoints_inserted) {
    166 
    167 	    for (bkpt = db_breakpoint_list;
    168 	         bkpt != 0;
    169 	         bkpt = bkpt->link)
    170 		if (db_map_current(bkpt->map)) {
    171 		    bkpt->bkpt_inst = db_get_value(bkpt->address,
    172 						   BKPT_SIZE,
    173 						   FALSE);
    174 		    db_put_value(bkpt->address,
    175 				 BKPT_SIZE,
    176 				 BKPT_SET(bkpt->bkpt_inst));
    177 		}
    178 	    db_breakpoints_inserted = TRUE;
    179 	}
    180 }
    181 
    182 void
    183 db_clear_breakpoints()
    184 {
    185 	register db_breakpoint_t	bkpt;
    186 
    187 	if (db_breakpoints_inserted) {
    188 
    189 	    for (bkpt = db_breakpoint_list;
    190 	         bkpt != 0;
    191 		 bkpt = bkpt->link)
    192 		if (db_map_current(bkpt->map)) {
    193 		    db_put_value(bkpt->address, BKPT_SIZE, bkpt->bkpt_inst);
    194 		}
    195 	    db_breakpoints_inserted = FALSE;
    196 	}
    197 }
    198 
    199 /*
    200  * Set a temporary breakpoint.
    201  * The instruction is changed immediately,
    202  * so the breakpoint does not have to be on the breakpoint list.
    203  */
    204 db_breakpoint_t
    205 db_set_temp_breakpoint(addr)
    206 	db_addr_t	addr;
    207 {
    208 	register db_breakpoint_t	bkpt;
    209 
    210 	bkpt = db_breakpoint_alloc();
    211 	if (bkpt == 0) {
    212 	    db_printf("Too many breakpoints.\n");
    213 	    return 0;
    214 	}
    215 
    216 	bkpt->map = NULL;
    217 	bkpt->address = addr;
    218 	bkpt->flags = BKPT_TEMP;
    219 	bkpt->init_count = 1;
    220 	bkpt->count = 1;
    221 
    222 	bkpt->bkpt_inst = db_get_value(bkpt->address, BKPT_SIZE, FALSE);
    223 	db_put_value(bkpt->address, BKPT_SIZE, BKPT_SET(bkpt->bkpt_inst));
    224 	return bkpt;
    225 }
    226 
    227 void
    228 db_delete_temp_breakpoint(bkpt)
    229 	db_breakpoint_t	bkpt;
    230 {
    231 	db_put_value(bkpt->address, BKPT_SIZE, bkpt->bkpt_inst);
    232 	db_breakpoint_free(bkpt);
    233 }
    234 
    235 /*
    236  * List breakpoints.
    237  */
    238 void
    239 db_list_breakpoints()
    240 {
    241 	register db_breakpoint_t	bkpt;
    242 
    243 	if (db_breakpoint_list == 0) {
    244 	    db_printf("No breakpoints set\n");
    245 	    return;
    246 	}
    247 
    248 	db_printf(" Map      Count    Address\n");
    249 	for (bkpt = db_breakpoint_list;
    250 	     bkpt != 0;
    251 	     bkpt = bkpt->link)
    252 	{
    253 	    db_printf("%s%8x %5d    ",
    254 		      db_map_current(bkpt->map) ? "*" : " ",
    255 		      bkpt->map, bkpt->init_count);
    256 	    db_printsym(bkpt->address, DB_STGY_PROC);
    257 	    db_printf("\n");
    258 	}
    259 }
    260 
    261 /* Delete breakpoint */
    262 /*ARGSUSED*/
    263 void
    264 db_delete_cmd(addr, have_addr, count, modif)
    265 	db_expr_t	addr;
    266 	int		have_addr;
    267 	db_expr_t	count;
    268 	char *		modif;
    269 {
    270 	db_delete_breakpoint(db_map_addr(addr), (db_addr_t)addr);
    271 }
    272 
    273 /* Set breakpoint with skip count */
    274 /*ARGSUSED*/
    275 void
    276 db_breakpoint_cmd(addr, have_addr, count, modif)
    277 	db_expr_t	addr;
    278 	int		have_addr;
    279 	db_expr_t	count;
    280 	char *		modif;
    281 {
    282 	if (count == -1)
    283 	    count = 1;
    284 
    285 	db_set_breakpoint(db_map_addr(addr), (db_addr_t)addr, count);
    286 }
    287 
    288 /* list breakpoints */
    289 /*ARGSUSED*/
    290 void
    291 db_listbreak_cmd(addr, have_addr, count, modif)
    292 	db_expr_t	addr;
    293 	int		have_addr;
    294 	db_expr_t	count;
    295 	char *		modif;
    296 {
    297 	db_list_breakpoints();
    298 }
    299 
    300 #include <vm/vm_kern.h>
    301 
    302 /*
    303  *	We want ddb to be usable before most of the kernel has been
    304  *	initialized.  In particular, current_thread() or kernel_map
    305  *	(or both) may be null.
    306  */
    307 
    308 boolean_t
    309 db_map_equal(map1, map2)
    310 	vm_map_t	map1, map2;
    311 {
    312 	return ((map1 == map2) ||
    313 		((map1 == NULL) && (map2 == kernel_map)) ||
    314 		((map1 == kernel_map) && (map2 == NULL)));
    315 }
    316 
    317 boolean_t
    318 db_map_current(map)
    319 	vm_map_t	map;
    320 {
    321 #if 0
    322 	thread_t	thread;
    323 
    324 	return ((map == NULL) ||
    325 		(map == kernel_map) ||
    326 		(((thread = current_thread()) != NULL) &&
    327 		 (map == thread->task->map)));
    328 #else
    329 	return (1);
    330 #endif
    331 }
    332 
    333 vm_map_t
    334 db_map_addr(addr)
    335 	vm_offset_t addr;
    336 {
    337 #if 0
    338 	thread_t	thread;
    339 
    340 	/*
    341 	 *	We want to return kernel_map for all
    342 	 *	non-user addresses, even when debugging
    343 	 *	kernel tasks with their own maps.
    344 	 */
    345 
    346 	if ((VM_MIN_ADDRESS <= addr) &&
    347 	    (addr < VM_MAX_ADDRESS) &&
    348 	    ((thread = current_thread()) != NULL))
    349 	    return thread->task->map;
    350 	else
    351 #endif
    352 	    return kernel_map;
    353 }
    354