Home | History | Annotate | Line # | Download | only in ddb
db_break.c revision 1.14
      1 /*	$NetBSD: db_break.c,v 1.14 2000/06/26 14:21:09 mrg 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: 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 	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 	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 	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 	db_breakpoint_t	bkpt;
    114 	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 	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 	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 	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  * List breakpoints.
    201  */
    202 void
    203 db_list_breakpoints()
    204 {
    205 	db_breakpoint_t	bkpt;
    206 
    207 	if (db_breakpoint_list == 0) {
    208 	    db_printf("No breakpoints set\n");
    209 	    return;
    210 	}
    211 
    212 	db_printf(" Map      Count    Address\n");
    213 	for (bkpt = db_breakpoint_list;
    214 	     bkpt != 0;
    215 	     bkpt = bkpt->link)
    216 	{
    217 	    db_printf("%s%p %5d    ",
    218 		      db_map_current(bkpt->map) ? "*" : " ",
    219 		      bkpt->map, bkpt->init_count);
    220 	    db_printsym(bkpt->address, DB_STGY_PROC, db_printf);
    221 	    db_printf("\n");
    222 	}
    223 }
    224 
    225 /* Delete breakpoint */
    226 /*ARGSUSED*/
    227 void
    228 db_delete_cmd(addr, have_addr, count, modif)
    229 	db_expr_t	addr;
    230 	int		have_addr;
    231 	db_expr_t	count;
    232 	char *		modif;
    233 {
    234 	db_delete_breakpoint(db_map_addr(addr), (db_addr_t)addr);
    235 }
    236 
    237 /* Set breakpoint with skip count */
    238 /*ARGSUSED*/
    239 void
    240 db_breakpoint_cmd(addr, have_addr, count, modif)
    241 	db_expr_t	addr;
    242 	int		have_addr;
    243 	db_expr_t	count;
    244 	char *		modif;
    245 {
    246 	if (count == -1)
    247 	    count = 1;
    248 
    249 	db_set_breakpoint(db_map_addr(addr), (db_addr_t)addr, count);
    250 }
    251 
    252 /* list breakpoints */
    253 /*ARGSUSED*/
    254 void
    255 db_listbreak_cmd(addr, have_addr, count, modif)
    256 	db_expr_t	addr;
    257 	int		have_addr;
    258 	db_expr_t	count;
    259 	char *		modif;
    260 {
    261 	db_list_breakpoints();
    262 }
    263 
    264 #include <uvm/uvm_extern.h>
    265 
    266 /*
    267  *	We want ddb to be usable before most of the kernel has been
    268  *	initialized.  In particular, current_thread() or kernel_map
    269  *	(or both) may be null.
    270  */
    271 
    272 boolean_t
    273 db_map_equal(map1, map2)
    274 	vm_map_t	map1, map2;
    275 {
    276 	return ((map1 == map2) ||
    277 		((map1 == NULL) && (map2 == kernel_map)) ||
    278 		((map1 == kernel_map) && (map2 == NULL)));
    279 }
    280 
    281 boolean_t
    282 db_map_current(map)
    283 	vm_map_t	map;
    284 {
    285 #if 0
    286 	thread_t	thread;
    287 
    288 	return ((map == NULL) ||
    289 		(map == kernel_map) ||
    290 		(((thread = current_thread()) != NULL) &&
    291 		 (map == thread->task->map)));
    292 #else
    293 	return (1);
    294 #endif
    295 }
    296 
    297 vm_map_t
    298 db_map_addr(addr)
    299 	vaddr_t addr;
    300 {
    301 #if 0
    302 	thread_t	thread;
    303 
    304 	/*
    305 	 *	We want to return kernel_map for all
    306 	 *	non-user addresses, even when debugging
    307 	 *	kernel tasks with their own maps.
    308 	 */
    309 
    310 	if ((VM_MIN_ADDRESS <= addr) &&
    311 	    (addr < VM_MAX_ADDRESS) &&
    312 	    ((thread = current_thread()) != NULL))
    313 	    return thread->task->map;
    314 	else
    315 #endif
    316 	    return kernel_map;
    317 }
    318