db_break.c revision 8876
18876Srgrimes/*
24Srgrimes * Mach Operating System
34Srgrimes * Copyright (c) 1991,1990 Carnegie Mellon University
44Srgrimes * All Rights Reserved.
58876Srgrimes *
64Srgrimes * Permission to use, copy, modify and distribute this software and its
74Srgrimes * documentation is hereby granted, provided that both the copyright
84Srgrimes * notice and this permission notice appear in all copies of the
94Srgrimes * software, derivative works or modified versions, and any portions
104Srgrimes * thereof, and that both notices appear in supporting documentation.
118876Srgrimes *
128876Srgrimes * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
134Srgrimes * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
144Srgrimes * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
158876Srgrimes *
164Srgrimes * Carnegie Mellon requests users of this software to return to
178876Srgrimes *
184Srgrimes *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
194Srgrimes *  School of Computer Science
204Srgrimes *  Carnegie Mellon University
214Srgrimes *  Pittsburgh PA 15213-3890
228876Srgrimes *
234Srgrimes * any improvements or extensions that they make and grant Carnegie the
244Srgrimes * rights to redistribute these changes.
254Srgrimes *
268876Srgrimes *	$Id: db_break.c,v 1.5 1994/08/18 22:34:19 wollman Exp $
274Srgrimes */
28623Srgrimes
294Srgrimes/*
304Srgrimes *	Author: David B. Golub, Carnegie Mellon University
314Srgrimes *	Date:	7/90
324Srgrimes */
334Srgrimes/*
344Srgrimes * Breakpoints.
354Srgrimes */
362056Swollman#include <sys/param.h>
372056Swollman#include <sys/systm.h>
382056Swollman#include <sys/proc.h>
392056Swollman#include <ddb/ddb.h>
404Srgrimes
414Srgrimes#include <ddb/db_lex.h>
424Srgrimes#include <ddb/db_break.h>
434Srgrimes#include <ddb/db_access.h>
444Srgrimes#include <ddb/db_sym.h>
454Srgrimes#include <ddb/db_break.h>
464Srgrimes
474Srgrimes#define	NBREAKPOINTS	100
484Srgrimesstruct db_breakpoint	db_break_table[NBREAKPOINTS];
494Srgrimesdb_breakpoint_t		db_next_free_breakpoint = &db_break_table[0];
504Srgrimesdb_breakpoint_t		db_free_breakpoints = 0;
514Srgrimesdb_breakpoint_t		db_breakpoint_list = 0;
524Srgrimes
534Srgrimesdb_breakpoint_t
544Srgrimesdb_breakpoint_alloc()
554Srgrimes{
564Srgrimes	register db_breakpoint_t	bkpt;
574Srgrimes
584Srgrimes	if ((bkpt = db_free_breakpoints) != 0) {
594Srgrimes	    db_free_breakpoints = bkpt->link;
604Srgrimes	    return (bkpt);
614Srgrimes	}
624Srgrimes	if (db_next_free_breakpoint == &db_break_table[NBREAKPOINTS]) {
634Srgrimes	    db_printf("All breakpoints used.\n");
644Srgrimes	    return (0);
654Srgrimes	}
664Srgrimes	bkpt = db_next_free_breakpoint;
674Srgrimes	db_next_free_breakpoint++;
684Srgrimes
694Srgrimes	return (bkpt);
704Srgrimes}
714Srgrimes
724Srgrimesvoid
734Srgrimesdb_breakpoint_free(bkpt)
744Srgrimes	register db_breakpoint_t	bkpt;
754Srgrimes{
764Srgrimes	bkpt->link = db_free_breakpoints;
774Srgrimes	db_free_breakpoints = bkpt;
784Srgrimes}
794Srgrimes
804Srgrimesvoid
814Srgrimesdb_set_breakpoint(map, addr, count)
824Srgrimes	vm_map_t	map;
834Srgrimes	db_addr_t	addr;
844Srgrimes	int		count;
854Srgrimes{
864Srgrimes	register db_breakpoint_t	bkpt;
874Srgrimes
884Srgrimes	if (db_find_breakpoint(map, addr)) {
894Srgrimes	    db_printf("Already set.\n");
904Srgrimes	    return;
914Srgrimes	}
924Srgrimes
934Srgrimes	bkpt = db_breakpoint_alloc();
944Srgrimes	if (bkpt == 0) {
954Srgrimes	    db_printf("Too many breakpoints.\n");
964Srgrimes	    return;
974Srgrimes	}
984Srgrimes
994Srgrimes	bkpt->map = map;
1004Srgrimes	bkpt->address = addr;
1014Srgrimes	bkpt->flags = 0;
1024Srgrimes	bkpt->init_count = count;
1034Srgrimes	bkpt->count = count;
1044Srgrimes
1054Srgrimes	bkpt->link = db_breakpoint_list;
1064Srgrimes	db_breakpoint_list = bkpt;
1074Srgrimes}
1084Srgrimes
1094Srgrimesvoid
1104Srgrimesdb_delete_breakpoint(map, addr)
1114Srgrimes	vm_map_t	map;
1124Srgrimes	db_addr_t	addr;
1134Srgrimes{
1144Srgrimes	register db_breakpoint_t	bkpt;
1154Srgrimes	register db_breakpoint_t	*prev;
1164Srgrimes
1174Srgrimes	for (prev = &db_breakpoint_list;
1184Srgrimes	     (bkpt = *prev) != 0;
1194Srgrimes	     prev = &bkpt->link) {
1204Srgrimes	    if (db_map_equal(bkpt->map, map) &&
1214Srgrimes		(bkpt->address == addr)) {
1224Srgrimes		*prev = bkpt->link;
1234Srgrimes		break;
1244Srgrimes	    }
1254Srgrimes	}
1264Srgrimes	if (bkpt == 0) {
1274Srgrimes	    db_printf("Not set.\n");
1284Srgrimes	    return;
1294Srgrimes	}
1304Srgrimes
1314Srgrimes	db_breakpoint_free(bkpt);
1324Srgrimes}
1334Srgrimes
1344Srgrimesdb_breakpoint_t
1354Srgrimesdb_find_breakpoint(map, addr)
1364Srgrimes	vm_map_t	map;
1374Srgrimes	db_addr_t	addr;
1384Srgrimes{
1394Srgrimes	register db_breakpoint_t	bkpt;
1404Srgrimes
1414Srgrimes	for (bkpt = db_breakpoint_list;
1424Srgrimes	     bkpt != 0;
1434Srgrimes	     bkpt = bkpt->link)
1444Srgrimes	{
1454Srgrimes	    if (db_map_equal(bkpt->map, map) &&
1464Srgrimes		(bkpt->address == addr))
1474Srgrimes		return (bkpt);
1484Srgrimes	}
1494Srgrimes	return (0);
1504Srgrimes}
1514Srgrimes
1524Srgrimesdb_breakpoint_t
1534Srgrimesdb_find_breakpoint_here(addr)
1544Srgrimes	db_addr_t	addr;
1554Srgrimes{
1564Srgrimes    return db_find_breakpoint(db_map_addr(addr), addr);
1574Srgrimes}
1584Srgrimes
1594Srgrimesboolean_t	db_breakpoints_inserted = TRUE;
1604Srgrimes
1614Srgrimesvoid
1624Srgrimesdb_set_breakpoints()
1634Srgrimes{
1644Srgrimes	register db_breakpoint_t	bkpt;
1654Srgrimes
1664Srgrimes	if (!db_breakpoints_inserted) {
1674Srgrimes
1684Srgrimes	    for (bkpt = db_breakpoint_list;
1694Srgrimes	         bkpt != 0;
1704Srgrimes	         bkpt = bkpt->link)
1714Srgrimes		if (db_map_current(bkpt->map)) {
1724Srgrimes		    bkpt->bkpt_inst = db_get_value(bkpt->address,
1734Srgrimes						   BKPT_SIZE,
1744Srgrimes						   FALSE);
1754Srgrimes		    db_put_value(bkpt->address,
1764Srgrimes				 BKPT_SIZE,
1774Srgrimes				 BKPT_SET(bkpt->bkpt_inst));
1784Srgrimes		}
1794Srgrimes	    db_breakpoints_inserted = TRUE;
1804Srgrimes	}
1814Srgrimes}
1824Srgrimes
1834Srgrimesvoid
1844Srgrimesdb_clear_breakpoints()
1854Srgrimes{
1864Srgrimes	register db_breakpoint_t	bkpt;
1874Srgrimes
1884Srgrimes	if (db_breakpoints_inserted) {
1894Srgrimes
1904Srgrimes	    for (bkpt = db_breakpoint_list;
1914Srgrimes	         bkpt != 0;
1924Srgrimes		 bkpt = bkpt->link)
1934Srgrimes		if (db_map_current(bkpt->map)) {
1944Srgrimes		    db_put_value(bkpt->address, BKPT_SIZE, bkpt->bkpt_inst);
1954Srgrimes		}
1964Srgrimes	    db_breakpoints_inserted = FALSE;
1974Srgrimes	}
1984Srgrimes}
1994Srgrimes
2004Srgrimes/*
2014Srgrimes * Set a temporary breakpoint.
2024Srgrimes * The instruction is changed immediately,
2034Srgrimes * so the breakpoint does not have to be on the breakpoint list.
2044Srgrimes */
2054Srgrimesdb_breakpoint_t
2064Srgrimesdb_set_temp_breakpoint(addr)
2074Srgrimes	db_addr_t	addr;
2084Srgrimes{
2094Srgrimes	register db_breakpoint_t	bkpt;
2104Srgrimes
2114Srgrimes	bkpt = db_breakpoint_alloc();
2124Srgrimes	if (bkpt == 0) {
2134Srgrimes	    db_printf("Too many breakpoints.\n");
2144Srgrimes	    return 0;
2154Srgrimes	}
2164Srgrimes
2174Srgrimes	bkpt->map = NULL;
2184Srgrimes	bkpt->address = addr;
2194Srgrimes	bkpt->flags = BKPT_TEMP;
2204Srgrimes	bkpt->init_count = 1;
2214Srgrimes	bkpt->count = 1;
2224Srgrimes
2234Srgrimes	bkpt->bkpt_inst = db_get_value(bkpt->address, BKPT_SIZE, FALSE);
2244Srgrimes	db_put_value(bkpt->address, BKPT_SIZE, BKPT_SET(bkpt->bkpt_inst));
2254Srgrimes	return bkpt;
2264Srgrimes}
2274Srgrimes
2284Srgrimesvoid
2294Srgrimesdb_delete_temp_breakpoint(bkpt)
2304Srgrimes	db_breakpoint_t	bkpt;
2314Srgrimes{
2324Srgrimes	db_put_value(bkpt->address, BKPT_SIZE, bkpt->bkpt_inst);
2334Srgrimes	db_breakpoint_free(bkpt);
2344Srgrimes}
2354Srgrimes
2364Srgrimes/*
2374Srgrimes * List breakpoints.
2384Srgrimes */
2394Srgrimesvoid
2404Srgrimesdb_list_breakpoints()
2414Srgrimes{
2424Srgrimes	register db_breakpoint_t	bkpt;
2434Srgrimes
2444Srgrimes	if (db_breakpoint_list == 0) {
2454Srgrimes	    db_printf("No breakpoints set\n");
2464Srgrimes	    return;
2474Srgrimes	}
2484Srgrimes
2494Srgrimes	db_printf(" Map      Count    Address\n");
2504Srgrimes	for (bkpt = db_breakpoint_list;
2514Srgrimes	     bkpt != 0;
2524Srgrimes	     bkpt = bkpt->link)
2534Srgrimes	{
2544Srgrimes	    db_printf("%s%8x %5d    ",
2554Srgrimes		      db_map_current(bkpt->map) ? "*" : " ",
2564Srgrimes		      bkpt->map, bkpt->init_count);
2574Srgrimes	    db_printsym(bkpt->address, DB_STGY_PROC);
2584Srgrimes	    db_printf("\n");
2594Srgrimes	}
2604Srgrimes}
2614Srgrimes
2624Srgrimes/* Delete breakpoint */
2634Srgrimes/*ARGSUSED*/
2644Srgrimesvoid
2654Srgrimesdb_delete_cmd(addr, have_addr, count, modif)
2664Srgrimes	db_expr_t	addr;
2674Srgrimes	int		have_addr;
2684Srgrimes	db_expr_t	count;
2694Srgrimes	char *		modif;
2704Srgrimes{
2714Srgrimes	db_delete_breakpoint(db_map_addr(addr), (db_addr_t)addr);
2724Srgrimes}
2734Srgrimes
2744Srgrimes/* Set breakpoint with skip count */
2754Srgrimes/*ARGSUSED*/
2764Srgrimesvoid
2774Srgrimesdb_breakpoint_cmd(addr, have_addr, count, modif)
2784Srgrimes	db_expr_t	addr;
2794Srgrimes	int		have_addr;
2804Srgrimes	db_expr_t	count;
2814Srgrimes	char *		modif;
2824Srgrimes{
2834Srgrimes	if (count == -1)
2844Srgrimes	    count = 1;
2854Srgrimes
2864Srgrimes	db_set_breakpoint(db_map_addr(addr), (db_addr_t)addr, count);
2874Srgrimes}
2884Srgrimes
2894Srgrimes/* list breakpoints */
2904Srgrimesvoid
291798Swollmandb_listbreak_cmd(db_expr_t dummy1, int dummy2, db_expr_t dummy3, char *dummy4)
2924Srgrimes{
2934Srgrimes	db_list_breakpoints();
2944Srgrimes}
2954Srgrimes
2964Srgrimes#include <vm/vm_kern.h>
2974Srgrimes
2984Srgrimes/*
2994Srgrimes *	We want ddb to be usable before most of the kernel has been
3004Srgrimes *	initialized.  In particular, current_thread() or kernel_map
3014Srgrimes *	(or both) may be null.
3024Srgrimes */
3034Srgrimes
3044Srgrimesboolean_t
3054Srgrimesdb_map_equal(map1, map2)
3064Srgrimes	vm_map_t	map1, map2;
3074Srgrimes{
3084Srgrimes	return ((map1 == map2) ||
3094Srgrimes		((map1 == NULL) && (map2 == kernel_map)) ||
3104Srgrimes		((map1 == kernel_map) && (map2 == NULL)));
3114Srgrimes}
3124Srgrimes
3134Srgrimesboolean_t
3144Srgrimesdb_map_current(map)
3154Srgrimes	vm_map_t	map;
3164Srgrimes{
3174Srgrimes#if 0
3184Srgrimes	thread_t	thread;
3194Srgrimes
3204Srgrimes	return ((map == NULL) ||
3214Srgrimes		(map == kernel_map) ||
3224Srgrimes		(((thread = current_thread()) != NULL) &&
3234Srgrimes		 (map == thread->task->map)));
3244Srgrimes#else
3254Srgrimes	return (1);
3264Srgrimes#endif
3274Srgrimes}
3284Srgrimes
3294Srgrimesvm_map_t
3304Srgrimesdb_map_addr(addr)
3314Srgrimes	vm_offset_t addr;
3324Srgrimes{
3334Srgrimes#if 0
3344Srgrimes	thread_t	thread;
3354Srgrimes
3364Srgrimes	/*
3374Srgrimes	 *	We want to return kernel_map for all
3384Srgrimes	 *	non-user addresses, even when debugging
3394Srgrimes	 *	kernel tasks with their own maps.
3404Srgrimes	 */
3414Srgrimes
3424Srgrimes	if ((VM_MIN_ADDRESS <= addr) &&
3434Srgrimes	    (addr < VM_MAX_ADDRESS) &&
3444Srgrimes	    ((thread = current_thread()) != NULL))
3454Srgrimes	    return thread->task->map;
3464Srgrimes	else
3474Srgrimes#endif
3484Srgrimes	    return kernel_map;
3494Srgrimes}
350