1139747Simp/*-
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 */
264Srgrimes/*
274Srgrimes * 	Author: Richard P. Draves, Carnegie Mellon University
284Srgrimes *	Date:	10/90
294Srgrimes */
304Srgrimes
31116176Sobrien#include <sys/cdefs.h>
32116176Sobrien__FBSDID("$FreeBSD$");
33116176Sobrien
342056Swollman#include <sys/param.h>
3533296Sbde#include <sys/kernel.h>
3676166Smarkm#include <sys/lock.h>
3776166Smarkm#include <sys/proc.h>
3812734Sbde
3912662Sdg#include <vm/vm.h>
4012662Sdg#include <vm/pmap.h>
4112662Sdg#include <vm/vm_map.h>
4212734Sbde
432056Swollman#include <ddb/ddb.h>
444Srgrimes#include <ddb/db_watch.h>
454Srgrimes
464Srgrimes/*
474Srgrimes * Watchpoints.
484Srgrimes */
494Srgrimes
5012515Sphkstatic boolean_t	db_watchpoints_inserted = TRUE;
514Srgrimes
524Srgrimes#define	NWATCHPOINTS	100
5312720Sphkstatic struct db_watchpoint	db_watch_table[NWATCHPOINTS];
5412515Sphkstatic db_watchpoint_t	db_next_free_watchpoint = &db_watch_table[0];
5512515Sphkstatic db_watchpoint_t	db_free_watchpoints = 0;
5612515Sphkstatic db_watchpoint_t	db_watchpoint_list = 0;
574Srgrimes
5892756Salfredstatic db_watchpoint_t	db_watchpoint_alloc(void);
5992756Salfredstatic void		db_watchpoint_free(db_watchpoint_t watch);
6092756Salfredstatic void		db_delete_watchpoint(vm_map_t map, db_addr_t addr);
6112515Sphk#ifdef notused
6292756Salfredstatic boolean_t	db_find_watchpoint(vm_map_t map, db_addr_t addr,
6392756Salfred					db_regs_t *regs);
6412515Sphk#endif
6592756Salfredstatic void		db_list_watchpoints(void);
6692756Salfredstatic void		db_set_watchpoint(vm_map_t map, db_addr_t addr,
6792756Salfred				       vm_size_t size);
6812473Sbde
69104094Sphkstatic db_watchpoint_t
704Srgrimesdb_watchpoint_alloc()
714Srgrimes{
724Srgrimes	register db_watchpoint_t	watch;
734Srgrimes
744Srgrimes	if ((watch = db_free_watchpoints) != 0) {
754Srgrimes	    db_free_watchpoints = watch->link;
764Srgrimes	    return (watch);
774Srgrimes	}
784Srgrimes	if (db_next_free_watchpoint == &db_watch_table[NWATCHPOINTS]) {
794Srgrimes	    db_printf("All watchpoints used.\n");
804Srgrimes	    return (0);
814Srgrimes	}
824Srgrimes	watch = db_next_free_watchpoint;
834Srgrimes	db_next_free_watchpoint++;
844Srgrimes
854Srgrimes	return (watch);
864Srgrimes}
874Srgrimes
88104094Sphkstatic void
894Srgrimesdb_watchpoint_free(watch)
904Srgrimes	register db_watchpoint_t	watch;
914Srgrimes{
924Srgrimes	watch->link = db_free_watchpoints;
934Srgrimes	db_free_watchpoints = watch;
944Srgrimes}
954Srgrimes
9612515Sphkstatic void
974Srgrimesdb_set_watchpoint(map, addr, size)
984Srgrimes	vm_map_t	map;
994Srgrimes	db_addr_t	addr;
1004Srgrimes	vm_size_t	size;
1014Srgrimes{
1024Srgrimes	register db_watchpoint_t	watch;
1034Srgrimes
1044Srgrimes	if (map == NULL) {
1054Srgrimes	    db_printf("No map.\n");
1064Srgrimes	    return;
1074Srgrimes	}
1084Srgrimes
1094Srgrimes	/*
1104Srgrimes	 *	Should we do anything fancy with overlapping regions?
1114Srgrimes	 */
1124Srgrimes
1134Srgrimes	for (watch = db_watchpoint_list;
1144Srgrimes	     watch != 0;
1154Srgrimes	     watch = watch->link)
1164Srgrimes	    if (db_map_equal(watch->map, map) &&
1174Srgrimes		(watch->loaddr == addr) &&
1184Srgrimes		(watch->hiaddr == addr+size)) {
1194Srgrimes		db_printf("Already set.\n");
1204Srgrimes		return;
1214Srgrimes	    }
1224Srgrimes
1234Srgrimes	watch = db_watchpoint_alloc();
1244Srgrimes	if (watch == 0) {
1254Srgrimes	    db_printf("Too many watchpoints.\n");
1264Srgrimes	    return;
1274Srgrimes	}
1284Srgrimes
1294Srgrimes	watch->map = map;
1304Srgrimes	watch->loaddr = addr;
1314Srgrimes	watch->hiaddr = addr+size;
1324Srgrimes
1334Srgrimes	watch->link = db_watchpoint_list;
1344Srgrimes	db_watchpoint_list = watch;
1354Srgrimes
1364Srgrimes	db_watchpoints_inserted = FALSE;
1374Srgrimes}
1384Srgrimes
13912515Sphkstatic void
1404Srgrimesdb_delete_watchpoint(map, addr)
1414Srgrimes	vm_map_t	map;
1424Srgrimes	db_addr_t	addr;
1434Srgrimes{
1444Srgrimes	register db_watchpoint_t	watch;
1454Srgrimes	register db_watchpoint_t	*prev;
1464Srgrimes
1474Srgrimes	for (prev = &db_watchpoint_list;
1484Srgrimes	     (watch = *prev) != 0;
1494Srgrimes	     prev = &watch->link)
1504Srgrimes	    if (db_map_equal(watch->map, map) &&
1514Srgrimes		(watch->loaddr <= addr) &&
1524Srgrimes		(addr < watch->hiaddr)) {
1534Srgrimes		*prev = watch->link;
1544Srgrimes		db_watchpoint_free(watch);
1554Srgrimes		return;
1564Srgrimes	    }
1574Srgrimes
1584Srgrimes	db_printf("Not set.\n");
1594Srgrimes}
1604Srgrimes
16112515Sphkstatic void
1624Srgrimesdb_list_watchpoints()
1634Srgrimes{
1644Srgrimes	register db_watchpoint_t	watch;
1654Srgrimes
1664Srgrimes	if (db_watchpoint_list == 0) {
1674Srgrimes	    db_printf("No watchpoints set\n");
1684Srgrimes	    return;
1694Srgrimes	}
1704Srgrimes
171164359Sjhb#ifdef __LP64__
172164359Sjhb	db_printf(" Map                Address          Size\n");
173164359Sjhb#else
1744Srgrimes	db_printf(" Map        Address  Size\n");
175164359Sjhb#endif
1764Srgrimes	for (watch = db_watchpoint_list;
1774Srgrimes	     watch != 0;
1784Srgrimes	     watch = watch->link)
179164359Sjhb#ifdef __LP64__
180164359Sjhb	    db_printf("%s%16p  %16lx  %lx\n",
181164359Sjhb#else
18248407Speter	    db_printf("%s%8p  %8lx  %lx\n",
183164359Sjhb#endif
1844Srgrimes		      db_map_current(watch->map) ? "*" : " ",
18548407Speter		      (void *)watch->map, (long)watch->loaddr,
18648407Speter		      (long)watch->hiaddr - (long)watch->loaddr);
1874Srgrimes}
1884Srgrimes
1894Srgrimes/* Delete watchpoint */
1904Srgrimes/*ARGSUSED*/
1914Srgrimesvoid
1924Srgrimesdb_deletewatch_cmd(addr, have_addr, count, modif)
1934Srgrimes	db_expr_t	addr;
19412473Sbde	boolean_t	have_addr;
1954Srgrimes	db_expr_t	count;
1964Srgrimes	char *		modif;
1974Srgrimes{
1984Srgrimes	db_delete_watchpoint(db_map_addr(addr), addr);
1994Srgrimes}
2004Srgrimes
2014Srgrimes/* Set watchpoint */
2024Srgrimes/*ARGSUSED*/
2034Srgrimesvoid
2044Srgrimesdb_watchpoint_cmd(addr, have_addr, count, modif)
2054Srgrimes	db_expr_t	addr;
20612473Sbde	boolean_t	have_addr;
2074Srgrimes	db_expr_t	count;
2084Srgrimes	char *		modif;
2094Srgrimes{
2104Srgrimes	vm_size_t	size;
2114Srgrimes	db_expr_t	value;
2124Srgrimes
2134Srgrimes	if (db_expression(&value))
2144Srgrimes	    size = (vm_size_t) value;
2154Srgrimes	else
2164Srgrimes	    size = 4;
2174Srgrimes	db_skip_to_eol();
2184Srgrimes
2194Srgrimes	db_set_watchpoint(db_map_addr(addr), addr, size);
2204Srgrimes}
2214Srgrimes
22233296Sbde/*
22333296Sbde * At least one non-optional show-command must be implemented using
22433296Sbde * DB_SHOW_COMMAND() so that db_show_cmd_set gets created.  Here is one.
22533296Sbde */
22633296SbdeDB_SHOW_COMMAND(watches, db_listwatch_cmd)
2274Srgrimes{
2284Srgrimes	db_list_watchpoints();
22979573Sbsd	db_md_list_watchpoints();
2304Srgrimes}
2314Srgrimes
2324Srgrimesvoid
2334Srgrimesdb_set_watchpoints()
2344Srgrimes{
2354Srgrimes	register db_watchpoint_t	watch;
2364Srgrimes
2374Srgrimes	if (!db_watchpoints_inserted) {
2384Srgrimes	    for (watch = db_watchpoint_list;
2394Srgrimes	         watch != 0;
2404Srgrimes	         watch = watch->link)
2414Srgrimes		pmap_protect(watch->map->pmap,
2424Srgrimes			     trunc_page(watch->loaddr),
2434Srgrimes			     round_page(watch->hiaddr),
2444Srgrimes			     VM_PROT_READ);
2454Srgrimes
2464Srgrimes	    db_watchpoints_inserted = TRUE;
2474Srgrimes	}
2484Srgrimes}
2494Srgrimes
2504Srgrimesvoid
2514Srgrimesdb_clear_watchpoints()
2524Srgrimes{
2534Srgrimes	db_watchpoints_inserted = FALSE;
2544Srgrimes}
2554Srgrimes
25612515Sphk#ifdef notused
25712515Sphkstatic boolean_t
2584Srgrimesdb_find_watchpoint(map, addr, regs)
2594Srgrimes	vm_map_t	map;
2604Srgrimes	db_addr_t	addr;
2614Srgrimes	db_regs_t	*regs;
2624Srgrimes{
2634Srgrimes	register db_watchpoint_t watch;
2644Srgrimes	db_watchpoint_t found = 0;
2654Srgrimes
2664Srgrimes	for (watch = db_watchpoint_list;
2674Srgrimes	     watch != 0;
2684Srgrimes	     watch = watch->link)
2694Srgrimes	    if (db_map_equal(watch->map, map)) {
2704Srgrimes		if ((watch->loaddr <= addr) &&
2714Srgrimes		    (addr < watch->hiaddr))
2724Srgrimes		    return (TRUE);
2734Srgrimes		else if ((trunc_page(watch->loaddr) <= addr) &&
2744Srgrimes			 (addr < round_page(watch->hiaddr)))
2754Srgrimes		    found = watch;
2764Srgrimes	    }
2774Srgrimes
2784Srgrimes	/*
2794Srgrimes	 *	We didn't hit exactly on a watchpoint, but we are
2804Srgrimes	 *	in a protected region.  We want to single-step
2814Srgrimes	 *	and then re-protect.
2824Srgrimes	 */
2834Srgrimes
2844Srgrimes	if (found) {
2854Srgrimes	    db_watchpoints_inserted = FALSE;
2864Srgrimes	    db_single_step(regs);
2874Srgrimes	}
2884Srgrimes
2894Srgrimes	return (FALSE);
2904Srgrimes}
29112515Sphk#endif
29279573Sbsd
29379573Sbsd
29479573Sbsd
29579573Sbsd/* Delete hardware watchpoint */
29679573Sbsd/*ARGSUSED*/
29779573Sbsdvoid
29879573Sbsddb_deletehwatch_cmd(addr, have_addr, count, modif)
29979573Sbsd	db_expr_t	addr;
30079573Sbsd	boolean_t	have_addr;
30179573Sbsd	db_expr_t	count;
30279573Sbsd	char *		modif;
30379573Sbsd{
30479573Sbsd	int rc;
30579573Sbsd
30679573Sbsd        if (count < 0)
30779573Sbsd                count = 4;
30879573Sbsd
30979573Sbsd	rc = db_md_clr_watchpoint(addr, count);
31079573Sbsd	if (rc < 0)
31179573Sbsd		db_printf("hardware watchpoint could not be deleted\n");
31279573Sbsd}
31379573Sbsd
31479573Sbsd/* Set hardware watchpoint */
31579573Sbsd/*ARGSUSED*/
31679573Sbsdvoid
31779573Sbsddb_hwatchpoint_cmd(addr, have_addr, count, modif)
31879573Sbsd	db_expr_t	addr;
31979573Sbsd	boolean_t	have_addr;
32079573Sbsd	db_expr_t	count;
32179573Sbsd	char *		modif;
32279573Sbsd{
32379573Sbsd	int rc;
32479573Sbsd
32579573Sbsd        if (count < 0)
32679573Sbsd                count = 4;
32779573Sbsd
32879573Sbsd	rc = db_md_set_watchpoint(addr, count);
32979573Sbsd	if (rc < 0)
33079573Sbsd		db_printf("hardware watchpoint could not be set\n");
33179573Sbsd}
332