db_break.c revision 83506
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 *
2650477Speter * $FreeBSD: head/sys/ddb/db_break.c 83506 2001-09-15 11:06:07Z dfr $
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>
3712734Sbde
3812662Sdg#include <vm/vm.h>
3912734Sbde#include <vm/vm_kern.h>
4012734Sbde
412056Swollman#include <ddb/ddb.h>
424Srgrimes#include <ddb/db_break.h>
434Srgrimes#include <ddb/db_access.h>
444Srgrimes#include <ddb/db_sym.h>
454Srgrimes
464Srgrimes#define	NBREAKPOINTS	100
4712720Sphkstatic struct db_breakpoint	db_break_table[NBREAKPOINTS];
4812515Sphkstatic db_breakpoint_t		db_next_free_breakpoint = &db_break_table[0];
4912515Sphkstatic db_breakpoint_t		db_free_breakpoints = 0;
5012515Sphkstatic db_breakpoint_t		db_breakpoint_list = 0;
514Srgrimes
5212515Sphkstatic db_breakpoint_t	db_breakpoint_alloc __P((void));
5312515Sphkstatic void	db_breakpoint_free __P((db_breakpoint_t bkpt));
5412515Sphkstatic void	db_delete_breakpoint __P((vm_map_t map, db_addr_t addr));
5512515Sphkstatic db_breakpoint_t	db_find_breakpoint __P((vm_map_t map, db_addr_t addr));
5612515Sphkstatic void	db_list_breakpoints __P((void));
5712515Sphkstatic void	db_set_breakpoint __P((vm_map_t map, db_addr_t addr,
5812515Sphk				       int count));
5912515Sphk
6012515Sphkstatic db_breakpoint_t
614Srgrimesdb_breakpoint_alloc()
624Srgrimes{
634Srgrimes	register db_breakpoint_t	bkpt;
644Srgrimes
654Srgrimes	if ((bkpt = db_free_breakpoints) != 0) {
664Srgrimes	    db_free_breakpoints = bkpt->link;
674Srgrimes	    return (bkpt);
684Srgrimes	}
694Srgrimes	if (db_next_free_breakpoint == &db_break_table[NBREAKPOINTS]) {
704Srgrimes	    db_printf("All breakpoints used.\n");
714Srgrimes	    return (0);
724Srgrimes	}
734Srgrimes	bkpt = db_next_free_breakpoint;
744Srgrimes	db_next_free_breakpoint++;
754Srgrimes
764Srgrimes	return (bkpt);
774Srgrimes}
784Srgrimes
7912515Sphkstatic void
804Srgrimesdb_breakpoint_free(bkpt)
814Srgrimes	register db_breakpoint_t	bkpt;
824Srgrimes{
834Srgrimes	bkpt->link = db_free_breakpoints;
844Srgrimes	db_free_breakpoints = bkpt;
854Srgrimes}
864Srgrimes
8712515Sphkstatic void
884Srgrimesdb_set_breakpoint(map, addr, count)
894Srgrimes	vm_map_t	map;
904Srgrimes	db_addr_t	addr;
914Srgrimes	int		count;
924Srgrimes{
934Srgrimes	register db_breakpoint_t	bkpt;
944Srgrimes
954Srgrimes	if (db_find_breakpoint(map, addr)) {
964Srgrimes	    db_printf("Already set.\n");
974Srgrimes	    return;
984Srgrimes	}
994Srgrimes
1004Srgrimes	bkpt = db_breakpoint_alloc();
1014Srgrimes	if (bkpt == 0) {
1024Srgrimes	    db_printf("Too many breakpoints.\n");
1034Srgrimes	    return;
1044Srgrimes	}
1054Srgrimes
1064Srgrimes	bkpt->map = map;
1074Srgrimes	bkpt->address = addr;
1084Srgrimes	bkpt->flags = 0;
1094Srgrimes	bkpt->init_count = count;
1104Srgrimes	bkpt->count = count;
1114Srgrimes
1124Srgrimes	bkpt->link = db_breakpoint_list;
1134Srgrimes	db_breakpoint_list = bkpt;
1144Srgrimes}
1154Srgrimes
11612515Sphkstatic void
1174Srgrimesdb_delete_breakpoint(map, addr)
1184Srgrimes	vm_map_t	map;
1194Srgrimes	db_addr_t	addr;
1204Srgrimes{
1214Srgrimes	register db_breakpoint_t	bkpt;
1224Srgrimes	register db_breakpoint_t	*prev;
1234Srgrimes
1244Srgrimes	for (prev = &db_breakpoint_list;
1254Srgrimes	     (bkpt = *prev) != 0;
1264Srgrimes	     prev = &bkpt->link) {
1274Srgrimes	    if (db_map_equal(bkpt->map, map) &&
1284Srgrimes		(bkpt->address == addr)) {
1294Srgrimes		*prev = bkpt->link;
1304Srgrimes		break;
1314Srgrimes	    }
1324Srgrimes	}
1334Srgrimes	if (bkpt == 0) {
1344Srgrimes	    db_printf("Not set.\n");
1354Srgrimes	    return;
1364Srgrimes	}
1374Srgrimes
1384Srgrimes	db_breakpoint_free(bkpt);
1394Srgrimes}
1404Srgrimes
14112515Sphkstatic db_breakpoint_t
1424Srgrimesdb_find_breakpoint(map, addr)
1434Srgrimes	vm_map_t	map;
1444Srgrimes	db_addr_t	addr;
1454Srgrimes{
1464Srgrimes	register db_breakpoint_t	bkpt;
1474Srgrimes
1484Srgrimes	for (bkpt = db_breakpoint_list;
1494Srgrimes	     bkpt != 0;
1504Srgrimes	     bkpt = bkpt->link)
1514Srgrimes	{
1524Srgrimes	    if (db_map_equal(bkpt->map, map) &&
1534Srgrimes		(bkpt->address == addr))
1544Srgrimes		return (bkpt);
1554Srgrimes	}
1564Srgrimes	return (0);
1574Srgrimes}
1584Srgrimes
1594Srgrimesdb_breakpoint_t
1604Srgrimesdb_find_breakpoint_here(addr)
1614Srgrimes	db_addr_t	addr;
1624Srgrimes{
1634Srgrimes    return db_find_breakpoint(db_map_addr(addr), addr);
1644Srgrimes}
1654Srgrimes
16612515Sphkstatic boolean_t	db_breakpoints_inserted = TRUE;
1674Srgrimes
16883506Sdfr#ifndef BKPT_WRITE
16983506Sdfr#define BKPT_WRITE(addr, storage)				\
17083506Sdfrdo {								\
17183506Sdfr	*storage = db_get_value(addr, BKPT_SIZE, FALSE);	\
17283506Sdfr	db_put_value(addr, BKPT_SIZE, BKPT_SET(*storage));	\
17383506Sdfr} while (0)
17483506Sdfr#endif
17583506Sdfr
17683506Sdfr#ifndef BKPT_CLEAR
17783506Sdfr#define BKPT_CLEAR(addr, storage) \
17883506Sdfr	db_put_value(addr, BKPT_SIZE, *storage)
17983506Sdfr#endif
18083506Sdfr
1814Srgrimesvoid
1824Srgrimesdb_set_breakpoints()
1834Srgrimes{
1844Srgrimes	register db_breakpoint_t	bkpt;
1854Srgrimes
1864Srgrimes	if (!db_breakpoints_inserted) {
1874Srgrimes
18883506Sdfr		for (bkpt = db_breakpoint_list;
18983506Sdfr		     bkpt != 0;
19083506Sdfr		     bkpt = bkpt->link)
19183506Sdfr			if (db_map_current(bkpt->map)) {
19283506Sdfr				BKPT_WRITE(bkpt->address, &bkpt->bkpt_inst);
19383506Sdfr			}
19483506Sdfr		db_breakpoints_inserted = TRUE;
1954Srgrimes	}
1964Srgrimes}
1974Srgrimes
1984Srgrimesvoid
1994Srgrimesdb_clear_breakpoints()
2004Srgrimes{
2014Srgrimes	register db_breakpoint_t	bkpt;
2024Srgrimes
2034Srgrimes	if (db_breakpoints_inserted) {
2044Srgrimes
20583506Sdfr		for (bkpt = db_breakpoint_list;
20683506Sdfr		     bkpt != 0;
20783506Sdfr		     bkpt = bkpt->link)
20883506Sdfr			if (db_map_current(bkpt->map)) {
20983506Sdfr				BKPT_CLEAR(bkpt->address, &bkpt->bkpt_inst);
21083506Sdfr			}
21183506Sdfr		db_breakpoints_inserted = FALSE;
2124Srgrimes	}
2134Srgrimes}
2144Srgrimes
21536735Sdfr#ifdef SOFTWARE_SSTEP
2164Srgrimes/*
2174Srgrimes * Set a temporary breakpoint.
2184Srgrimes * The instruction is changed immediately,
2194Srgrimes * so the breakpoint does not have to be on the breakpoint list.
2204Srgrimes */
22136735Sdfrdb_breakpoint_t
2224Srgrimesdb_set_temp_breakpoint(addr)
2234Srgrimes	db_addr_t	addr;
2244Srgrimes{
2254Srgrimes	register db_breakpoint_t	bkpt;
2264Srgrimes
2274Srgrimes	bkpt = db_breakpoint_alloc();
2284Srgrimes	if (bkpt == 0) {
2294Srgrimes	    db_printf("Too many breakpoints.\n");
2304Srgrimes	    return 0;
2314Srgrimes	}
2324Srgrimes
2334Srgrimes	bkpt->map = NULL;
2344Srgrimes	bkpt->address = addr;
2354Srgrimes	bkpt->flags = BKPT_TEMP;
2364Srgrimes	bkpt->init_count = 1;
2374Srgrimes	bkpt->count = 1;
2384Srgrimes
23983506Sdfr	BKPT_WRITE(bkpt->address, &bkpt->bkpt_inst);
2404Srgrimes	return bkpt;
2414Srgrimes}
2424Srgrimes
24336735Sdfrvoid
2444Srgrimesdb_delete_temp_breakpoint(bkpt)
2454Srgrimes	db_breakpoint_t	bkpt;
2464Srgrimes{
24783506Sdfr	BKPT_CLEAR(bkpt->address, &bkpt->bkpt_inst);
2484Srgrimes	db_breakpoint_free(bkpt);
2494Srgrimes}
25036745Sbde#endif /* SOFTWARE_SSTEP */
25136735Sdfr
2524Srgrimes/*
2534Srgrimes * List breakpoints.
2544Srgrimes */
25512515Sphkstatic void
2564Srgrimesdb_list_breakpoints()
2574Srgrimes{
2584Srgrimes	register db_breakpoint_t	bkpt;
2594Srgrimes
2604Srgrimes	if (db_breakpoint_list == 0) {
2614Srgrimes	    db_printf("No breakpoints set\n");
2624Srgrimes	    return;
2634Srgrimes	}
2644Srgrimes
2654Srgrimes	db_printf(" Map      Count    Address\n");
2664Srgrimes	for (bkpt = db_breakpoint_list;
2674Srgrimes	     bkpt != 0;
26837497Sbde	     bkpt = bkpt->link) {
26937497Sbde	    db_printf("%s%8p %5d    ",
2704Srgrimes		      db_map_current(bkpt->map) ? "*" : " ",
27137497Sbde		      (void *)bkpt->map, bkpt->init_count);
2724Srgrimes	    db_printsym(bkpt->address, DB_STGY_PROC);
2734Srgrimes	    db_printf("\n");
2744Srgrimes	}
2754Srgrimes}
2764Srgrimes
2774Srgrimes/* Delete breakpoint */
2784Srgrimes/*ARGSUSED*/
2794Srgrimesvoid
2804Srgrimesdb_delete_cmd(addr, have_addr, count, modif)
2814Srgrimes	db_expr_t	addr;
28212473Sbde	boolean_t	have_addr;
2834Srgrimes	db_expr_t	count;
2844Srgrimes	char *		modif;
2854Srgrimes{
2864Srgrimes	db_delete_breakpoint(db_map_addr(addr), (db_addr_t)addr);
2874Srgrimes}
2884Srgrimes
2894Srgrimes/* Set breakpoint with skip count */
2904Srgrimes/*ARGSUSED*/
2914Srgrimesvoid
2924Srgrimesdb_breakpoint_cmd(addr, have_addr, count, modif)
2934Srgrimes	db_expr_t	addr;
29412473Sbde	boolean_t	have_addr;
2954Srgrimes	db_expr_t	count;
2964Srgrimes	char *		modif;
2974Srgrimes{
2984Srgrimes	if (count == -1)
2994Srgrimes	    count = 1;
3004Srgrimes
3014Srgrimes	db_set_breakpoint(db_map_addr(addr), (db_addr_t)addr, count);
3024Srgrimes}
3034Srgrimes
3044Srgrimes/* list breakpoints */
3054Srgrimesvoid
30612473Sbdedb_listbreak_cmd(dummy1, dummy2, dummy3, dummy4)
30712473Sbde	db_expr_t	dummy1;
30812473Sbde	boolean_t	dummy2;
30912473Sbde	db_expr_t	dummy3;
31012473Sbde	char *		dummy4;
3114Srgrimes{
3124Srgrimes	db_list_breakpoints();
3134Srgrimes}
3144Srgrimes
3154Srgrimes/*
3164Srgrimes *	We want ddb to be usable before most of the kernel has been
3174Srgrimes *	initialized.  In particular, current_thread() or kernel_map
3184Srgrimes *	(or both) may be null.
3194Srgrimes */
3204Srgrimes
3214Srgrimesboolean_t
3224Srgrimesdb_map_equal(map1, map2)
3234Srgrimes	vm_map_t	map1, map2;
3244Srgrimes{
3254Srgrimes	return ((map1 == map2) ||
3264Srgrimes		((map1 == NULL) && (map2 == kernel_map)) ||
3274Srgrimes		((map1 == kernel_map) && (map2 == NULL)));
3284Srgrimes}
3294Srgrimes
3304Srgrimesboolean_t
3314Srgrimesdb_map_current(map)
3324Srgrimes	vm_map_t	map;
3334Srgrimes{
3344Srgrimes#if 0
3354Srgrimes	thread_t	thread;
3364Srgrimes
3374Srgrimes	return ((map == NULL) ||
3384Srgrimes		(map == kernel_map) ||
3394Srgrimes		(((thread = current_thread()) != NULL) &&
3404Srgrimes		 (map == thread->task->map)));
3414Srgrimes#else
3424Srgrimes	return (1);
3434Srgrimes#endif
3444Srgrimes}
3454Srgrimes
3464Srgrimesvm_map_t
3474Srgrimesdb_map_addr(addr)
3484Srgrimes	vm_offset_t addr;
3494Srgrimes{
3504Srgrimes#if 0
3514Srgrimes	thread_t	thread;
3524Srgrimes
3534Srgrimes	/*
3544Srgrimes	 *	We want to return kernel_map for all
3554Srgrimes	 *	non-user addresses, even when debugging
3564Srgrimes	 *	kernel tasks with their own maps.
3574Srgrimes	 */
3584Srgrimes
3594Srgrimes	if ((VM_MIN_ADDRESS <= addr) &&
3604Srgrimes	    (addr < VM_MAX_ADDRESS) &&
3614Srgrimes	    ((thread = current_thread()) != NULL))
3624Srgrimes	    return thread->task->map;
3634Srgrimes	else
3644Srgrimes#endif
3654Srgrimes	    return kernel_map;
3664Srgrimes}
367