db_break.c revision 92756
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 92756 2002-03-20 05:14:42Z alfred $
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
5292756Salfredstatic db_breakpoint_t	db_breakpoint_alloc(void);
5392756Salfredstatic void	db_breakpoint_free(db_breakpoint_t bkpt);
5492756Salfredstatic void	db_delete_breakpoint(vm_map_t map, db_addr_t addr);
5592756Salfredstatic db_breakpoint_t	db_find_breakpoint(vm_map_t map, db_addr_t addr);
5692756Salfredstatic void	db_list_breakpoints(void);
5792756Salfredstatic void	db_set_breakpoint(vm_map_t map, db_addr_t addr, int count);
5812515Sphk
5912515Sphkstatic db_breakpoint_t
604Srgrimesdb_breakpoint_alloc()
614Srgrimes{
624Srgrimes	register db_breakpoint_t	bkpt;
634Srgrimes
644Srgrimes	if ((bkpt = db_free_breakpoints) != 0) {
654Srgrimes	    db_free_breakpoints = bkpt->link;
664Srgrimes	    return (bkpt);
674Srgrimes	}
684Srgrimes	if (db_next_free_breakpoint == &db_break_table[NBREAKPOINTS]) {
694Srgrimes	    db_printf("All breakpoints used.\n");
704Srgrimes	    return (0);
714Srgrimes	}
724Srgrimes	bkpt = db_next_free_breakpoint;
734Srgrimes	db_next_free_breakpoint++;
744Srgrimes
754Srgrimes	return (bkpt);
764Srgrimes}
774Srgrimes
7812515Sphkstatic void
794Srgrimesdb_breakpoint_free(bkpt)
804Srgrimes	register db_breakpoint_t	bkpt;
814Srgrimes{
824Srgrimes	bkpt->link = db_free_breakpoints;
834Srgrimes	db_free_breakpoints = bkpt;
844Srgrimes}
854Srgrimes
8612515Sphkstatic void
874Srgrimesdb_set_breakpoint(map, addr, count)
884Srgrimes	vm_map_t	map;
894Srgrimes	db_addr_t	addr;
904Srgrimes	int		count;
914Srgrimes{
924Srgrimes	register db_breakpoint_t	bkpt;
934Srgrimes
944Srgrimes	if (db_find_breakpoint(map, addr)) {
954Srgrimes	    db_printf("Already set.\n");
964Srgrimes	    return;
974Srgrimes	}
984Srgrimes
994Srgrimes	bkpt = db_breakpoint_alloc();
1004Srgrimes	if (bkpt == 0) {
1014Srgrimes	    db_printf("Too many breakpoints.\n");
1024Srgrimes	    return;
1034Srgrimes	}
1044Srgrimes
1054Srgrimes	bkpt->map = map;
1064Srgrimes	bkpt->address = addr;
1074Srgrimes	bkpt->flags = 0;
1084Srgrimes	bkpt->init_count = count;
1094Srgrimes	bkpt->count = count;
1104Srgrimes
1114Srgrimes	bkpt->link = db_breakpoint_list;
1124Srgrimes	db_breakpoint_list = bkpt;
1134Srgrimes}
1144Srgrimes
11512515Sphkstatic void
1164Srgrimesdb_delete_breakpoint(map, addr)
1174Srgrimes	vm_map_t	map;
1184Srgrimes	db_addr_t	addr;
1194Srgrimes{
1204Srgrimes	register db_breakpoint_t	bkpt;
1214Srgrimes	register db_breakpoint_t	*prev;
1224Srgrimes
1234Srgrimes	for (prev = &db_breakpoint_list;
1244Srgrimes	     (bkpt = *prev) != 0;
1254Srgrimes	     prev = &bkpt->link) {
1264Srgrimes	    if (db_map_equal(bkpt->map, map) &&
1274Srgrimes		(bkpt->address == addr)) {
1284Srgrimes		*prev = bkpt->link;
1294Srgrimes		break;
1304Srgrimes	    }
1314Srgrimes	}
1324Srgrimes	if (bkpt == 0) {
1334Srgrimes	    db_printf("Not set.\n");
1344Srgrimes	    return;
1354Srgrimes	}
1364Srgrimes
1374Srgrimes	db_breakpoint_free(bkpt);
1384Srgrimes}
1394Srgrimes
14012515Sphkstatic db_breakpoint_t
1414Srgrimesdb_find_breakpoint(map, addr)
1424Srgrimes	vm_map_t	map;
1434Srgrimes	db_addr_t	addr;
1444Srgrimes{
1454Srgrimes	register db_breakpoint_t	bkpt;
1464Srgrimes
1474Srgrimes	for (bkpt = db_breakpoint_list;
1484Srgrimes	     bkpt != 0;
1494Srgrimes	     bkpt = bkpt->link)
1504Srgrimes	{
1514Srgrimes	    if (db_map_equal(bkpt->map, map) &&
1524Srgrimes		(bkpt->address == addr))
1534Srgrimes		return (bkpt);
1544Srgrimes	}
1554Srgrimes	return (0);
1564Srgrimes}
1574Srgrimes
1584Srgrimesdb_breakpoint_t
1594Srgrimesdb_find_breakpoint_here(addr)
1604Srgrimes	db_addr_t	addr;
1614Srgrimes{
1624Srgrimes    return db_find_breakpoint(db_map_addr(addr), addr);
1634Srgrimes}
1644Srgrimes
16512515Sphkstatic boolean_t	db_breakpoints_inserted = TRUE;
1664Srgrimes
16783506Sdfr#ifndef BKPT_WRITE
16883506Sdfr#define BKPT_WRITE(addr, storage)				\
16983506Sdfrdo {								\
17083506Sdfr	*storage = db_get_value(addr, BKPT_SIZE, FALSE);	\
17183506Sdfr	db_put_value(addr, BKPT_SIZE, BKPT_SET(*storage));	\
17283506Sdfr} while (0)
17383506Sdfr#endif
17483506Sdfr
17583506Sdfr#ifndef BKPT_CLEAR
17683506Sdfr#define BKPT_CLEAR(addr, storage) \
17783506Sdfr	db_put_value(addr, BKPT_SIZE, *storage)
17883506Sdfr#endif
17983506Sdfr
1804Srgrimesvoid
1814Srgrimesdb_set_breakpoints()
1824Srgrimes{
1834Srgrimes	register db_breakpoint_t	bkpt;
1844Srgrimes
1854Srgrimes	if (!db_breakpoints_inserted) {
1864Srgrimes
18783506Sdfr		for (bkpt = db_breakpoint_list;
18883506Sdfr		     bkpt != 0;
18983506Sdfr		     bkpt = bkpt->link)
19083506Sdfr			if (db_map_current(bkpt->map)) {
19183506Sdfr				BKPT_WRITE(bkpt->address, &bkpt->bkpt_inst);
19283506Sdfr			}
19383506Sdfr		db_breakpoints_inserted = TRUE;
1944Srgrimes	}
1954Srgrimes}
1964Srgrimes
1974Srgrimesvoid
1984Srgrimesdb_clear_breakpoints()
1994Srgrimes{
2004Srgrimes	register db_breakpoint_t	bkpt;
2014Srgrimes
2024Srgrimes	if (db_breakpoints_inserted) {
2034Srgrimes
20483506Sdfr		for (bkpt = db_breakpoint_list;
20583506Sdfr		     bkpt != 0;
20683506Sdfr		     bkpt = bkpt->link)
20783506Sdfr			if (db_map_current(bkpt->map)) {
20883506Sdfr				BKPT_CLEAR(bkpt->address, &bkpt->bkpt_inst);
20983506Sdfr			}
21083506Sdfr		db_breakpoints_inserted = FALSE;
2114Srgrimes	}
2124Srgrimes}
2134Srgrimes
21436735Sdfr#ifdef SOFTWARE_SSTEP
2154Srgrimes/*
2164Srgrimes * Set a temporary breakpoint.
2174Srgrimes * The instruction is changed immediately,
2184Srgrimes * so the breakpoint does not have to be on the breakpoint list.
2194Srgrimes */
22036735Sdfrdb_breakpoint_t
2214Srgrimesdb_set_temp_breakpoint(addr)
2224Srgrimes	db_addr_t	addr;
2234Srgrimes{
2244Srgrimes	register db_breakpoint_t	bkpt;
2254Srgrimes
2264Srgrimes	bkpt = db_breakpoint_alloc();
2274Srgrimes	if (bkpt == 0) {
2284Srgrimes	    db_printf("Too many breakpoints.\n");
2294Srgrimes	    return 0;
2304Srgrimes	}
2314Srgrimes
2324Srgrimes	bkpt->map = NULL;
2334Srgrimes	bkpt->address = addr;
2344Srgrimes	bkpt->flags = BKPT_TEMP;
2354Srgrimes	bkpt->init_count = 1;
2364Srgrimes	bkpt->count = 1;
2374Srgrimes
23883506Sdfr	BKPT_WRITE(bkpt->address, &bkpt->bkpt_inst);
2394Srgrimes	return bkpt;
2404Srgrimes}
2414Srgrimes
24236735Sdfrvoid
2434Srgrimesdb_delete_temp_breakpoint(bkpt)
2444Srgrimes	db_breakpoint_t	bkpt;
2454Srgrimes{
24683506Sdfr	BKPT_CLEAR(bkpt->address, &bkpt->bkpt_inst);
2474Srgrimes	db_breakpoint_free(bkpt);
2484Srgrimes}
24936745Sbde#endif /* SOFTWARE_SSTEP */
25036735Sdfr
2514Srgrimes/*
2524Srgrimes * List breakpoints.
2534Srgrimes */
25412515Sphkstatic void
2554Srgrimesdb_list_breakpoints()
2564Srgrimes{
2574Srgrimes	register db_breakpoint_t	bkpt;
2584Srgrimes
2594Srgrimes	if (db_breakpoint_list == 0) {
2604Srgrimes	    db_printf("No breakpoints set\n");
2614Srgrimes	    return;
2624Srgrimes	}
2634Srgrimes
2644Srgrimes	db_printf(" Map      Count    Address\n");
2654Srgrimes	for (bkpt = db_breakpoint_list;
2664Srgrimes	     bkpt != 0;
26737497Sbde	     bkpt = bkpt->link) {
26837497Sbde	    db_printf("%s%8p %5d    ",
2694Srgrimes		      db_map_current(bkpt->map) ? "*" : " ",
27037497Sbde		      (void *)bkpt->map, bkpt->init_count);
2714Srgrimes	    db_printsym(bkpt->address, DB_STGY_PROC);
2724Srgrimes	    db_printf("\n");
2734Srgrimes	}
2744Srgrimes}
2754Srgrimes
2764Srgrimes/* Delete breakpoint */
2774Srgrimes/*ARGSUSED*/
2784Srgrimesvoid
2794Srgrimesdb_delete_cmd(addr, have_addr, count, modif)
2804Srgrimes	db_expr_t	addr;
28112473Sbde	boolean_t	have_addr;
2824Srgrimes	db_expr_t	count;
2834Srgrimes	char *		modif;
2844Srgrimes{
2854Srgrimes	db_delete_breakpoint(db_map_addr(addr), (db_addr_t)addr);
2864Srgrimes}
2874Srgrimes
2884Srgrimes/* Set breakpoint with skip count */
2894Srgrimes/*ARGSUSED*/
2904Srgrimesvoid
2914Srgrimesdb_breakpoint_cmd(addr, have_addr, count, modif)
2924Srgrimes	db_expr_t	addr;
29312473Sbde	boolean_t	have_addr;
2944Srgrimes	db_expr_t	count;
2954Srgrimes	char *		modif;
2964Srgrimes{
2974Srgrimes	if (count == -1)
2984Srgrimes	    count = 1;
2994Srgrimes
3004Srgrimes	db_set_breakpoint(db_map_addr(addr), (db_addr_t)addr, count);
3014Srgrimes}
3024Srgrimes
3034Srgrimes/* list breakpoints */
3044Srgrimesvoid
30512473Sbdedb_listbreak_cmd(dummy1, dummy2, dummy3, dummy4)
30612473Sbde	db_expr_t	dummy1;
30712473Sbde	boolean_t	dummy2;
30812473Sbde	db_expr_t	dummy3;
30912473Sbde	char *		dummy4;
3104Srgrimes{
3114Srgrimes	db_list_breakpoints();
3124Srgrimes}
3134Srgrimes
3144Srgrimes/*
3154Srgrimes *	We want ddb to be usable before most of the kernel has been
3164Srgrimes *	initialized.  In particular, current_thread() or kernel_map
3174Srgrimes *	(or both) may be null.
3184Srgrimes */
3194Srgrimes
3204Srgrimesboolean_t
3214Srgrimesdb_map_equal(map1, map2)
3224Srgrimes	vm_map_t	map1, map2;
3234Srgrimes{
3244Srgrimes	return ((map1 == map2) ||
3254Srgrimes		((map1 == NULL) && (map2 == kernel_map)) ||
3264Srgrimes		((map1 == kernel_map) && (map2 == NULL)));
3274Srgrimes}
3284Srgrimes
3294Srgrimesboolean_t
3304Srgrimesdb_map_current(map)
3314Srgrimes	vm_map_t	map;
3324Srgrimes{
3334Srgrimes#if 0
3344Srgrimes	thread_t	thread;
3354Srgrimes
3364Srgrimes	return ((map == NULL) ||
3374Srgrimes		(map == kernel_map) ||
3384Srgrimes		(((thread = current_thread()) != NULL) &&
3394Srgrimes		 (map == thread->task->map)));
3404Srgrimes#else
3414Srgrimes	return (1);
3424Srgrimes#endif
3434Srgrimes}
3444Srgrimes
3454Srgrimesvm_map_t
3464Srgrimesdb_map_addr(addr)
3474Srgrimes	vm_offset_t addr;
3484Srgrimes{
3494Srgrimes#if 0
3504Srgrimes	thread_t	thread;
3514Srgrimes
3524Srgrimes	/*
3534Srgrimes	 *	We want to return kernel_map for all
3544Srgrimes	 *	non-user addresses, even when debugging
3554Srgrimes	 *	kernel tasks with their own maps.
3564Srgrimes	 */
3574Srgrimes
3584Srgrimes	if ((VM_MIN_ADDRESS <= addr) &&
3594Srgrimes	    (addr < VM_MAX_ADDRESS) &&
3604Srgrimes	    ((thread = current_thread()) != NULL))
3614Srgrimes	    return thread->task->map;
3624Srgrimes	else
3634Srgrimes#endif
3644Srgrimes	    return kernel_map;
3654Srgrimes}
366