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 70273265Spfgdb_watchpoint_alloc(void) 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 89273265Spfgdb_watchpoint_free(db_watchpoint_t watch) 904Srgrimes{ 914Srgrimes watch->link = db_free_watchpoints; 924Srgrimes db_free_watchpoints = watch; 934Srgrimes} 944Srgrimes 9512515Sphkstatic void 96273265Spfgdb_set_watchpoint(vm_map_t map, db_addr_t addr, vm_size_t size) 974Srgrimes{ 984Srgrimes register db_watchpoint_t watch; 994Srgrimes 1004Srgrimes if (map == NULL) { 1014Srgrimes db_printf("No map.\n"); 1024Srgrimes return; 1034Srgrimes } 1044Srgrimes 1054Srgrimes /* 1064Srgrimes * Should we do anything fancy with overlapping regions? 1074Srgrimes */ 1084Srgrimes 1094Srgrimes for (watch = db_watchpoint_list; 1104Srgrimes watch != 0; 1114Srgrimes watch = watch->link) 1124Srgrimes if (db_map_equal(watch->map, map) && 1134Srgrimes (watch->loaddr == addr) && 1144Srgrimes (watch->hiaddr == addr+size)) { 1154Srgrimes db_printf("Already set.\n"); 1164Srgrimes return; 1174Srgrimes } 1184Srgrimes 1194Srgrimes watch = db_watchpoint_alloc(); 1204Srgrimes if (watch == 0) { 1214Srgrimes db_printf("Too many watchpoints.\n"); 1224Srgrimes return; 1234Srgrimes } 1244Srgrimes 1254Srgrimes watch->map = map; 1264Srgrimes watch->loaddr = addr; 1274Srgrimes watch->hiaddr = addr+size; 1284Srgrimes 1294Srgrimes watch->link = db_watchpoint_list; 1304Srgrimes db_watchpoint_list = watch; 1314Srgrimes 1324Srgrimes db_watchpoints_inserted = FALSE; 1334Srgrimes} 1344Srgrimes 13512515Sphkstatic void 136273265Spfgdb_delete_watchpoint(vm_map_t map, db_addr_t addr) 1374Srgrimes{ 1384Srgrimes register db_watchpoint_t watch; 1394Srgrimes register db_watchpoint_t *prev; 1404Srgrimes 1414Srgrimes for (prev = &db_watchpoint_list; 1424Srgrimes (watch = *prev) != 0; 1434Srgrimes prev = &watch->link) 1444Srgrimes if (db_map_equal(watch->map, map) && 1454Srgrimes (watch->loaddr <= addr) && 1464Srgrimes (addr < watch->hiaddr)) { 1474Srgrimes *prev = watch->link; 1484Srgrimes db_watchpoint_free(watch); 1494Srgrimes return; 1504Srgrimes } 1514Srgrimes 1524Srgrimes db_printf("Not set.\n"); 1534Srgrimes} 1544Srgrimes 15512515Sphkstatic void 156273265Spfgdb_list_watchpoints(void) 1574Srgrimes{ 1584Srgrimes register db_watchpoint_t watch; 1594Srgrimes 1604Srgrimes if (db_watchpoint_list == 0) { 1614Srgrimes db_printf("No watchpoints set\n"); 1624Srgrimes return; 1634Srgrimes } 1644Srgrimes 165164359Sjhb#ifdef __LP64__ 166164359Sjhb db_printf(" Map Address Size\n"); 167164359Sjhb#else 1684Srgrimes db_printf(" Map Address Size\n"); 169164359Sjhb#endif 1704Srgrimes for (watch = db_watchpoint_list; 1714Srgrimes watch != 0; 1724Srgrimes watch = watch->link) 173164359Sjhb#ifdef __LP64__ 174164359Sjhb db_printf("%s%16p %16lx %lx\n", 175164359Sjhb#else 17648407Speter db_printf("%s%8p %8lx %lx\n", 177164359Sjhb#endif 1784Srgrimes db_map_current(watch->map) ? "*" : " ", 17948407Speter (void *)watch->map, (long)watch->loaddr, 18048407Speter (long)watch->hiaddr - (long)watch->loaddr); 1814Srgrimes} 1824Srgrimes 1834Srgrimes/* Delete watchpoint */ 1844Srgrimes/*ARGSUSED*/ 1854Srgrimesvoid 186273265Spfgdb_deletewatch_cmd(db_expr_t addr, boolean_t have_addr, db_expr_t count, 187273265Spfg char *modif) 1884Srgrimes{ 1894Srgrimes db_delete_watchpoint(db_map_addr(addr), addr); 1904Srgrimes} 1914Srgrimes 1924Srgrimes/* Set watchpoint */ 1934Srgrimes/*ARGSUSED*/ 1944Srgrimesvoid 195273265Spfgdb_watchpoint_cmd(db_expr_t addr, boolean_t have_addr, db_expr_t count, 196273265Spfg char *modif) 1974Srgrimes{ 1984Srgrimes vm_size_t size; 1994Srgrimes db_expr_t value; 2004Srgrimes 2014Srgrimes if (db_expression(&value)) 2024Srgrimes size = (vm_size_t) value; 2034Srgrimes else 2044Srgrimes size = 4; 2054Srgrimes db_skip_to_eol(); 2064Srgrimes 2074Srgrimes db_set_watchpoint(db_map_addr(addr), addr, size); 2084Srgrimes} 2094Srgrimes 21033296Sbde/* 21133296Sbde * At least one non-optional show-command must be implemented using 21233296Sbde * DB_SHOW_COMMAND() so that db_show_cmd_set gets created. Here is one. 21333296Sbde */ 21433296SbdeDB_SHOW_COMMAND(watches, db_listwatch_cmd) 2154Srgrimes{ 2164Srgrimes db_list_watchpoints(); 21779573Sbsd db_md_list_watchpoints(); 2184Srgrimes} 2194Srgrimes 2204Srgrimesvoid 221273265Spfgdb_set_watchpoints(void) 2224Srgrimes{ 2234Srgrimes register db_watchpoint_t watch; 2244Srgrimes 2254Srgrimes if (!db_watchpoints_inserted) { 2264Srgrimes for (watch = db_watchpoint_list; 2274Srgrimes watch != 0; 2284Srgrimes watch = watch->link) 2294Srgrimes pmap_protect(watch->map->pmap, 2304Srgrimes trunc_page(watch->loaddr), 2314Srgrimes round_page(watch->hiaddr), 2324Srgrimes VM_PROT_READ); 2334Srgrimes 2344Srgrimes db_watchpoints_inserted = TRUE; 2354Srgrimes } 2364Srgrimes} 2374Srgrimes 2384Srgrimesvoid 239273265Spfgdb_clear_watchpoints(void) 2404Srgrimes{ 2414Srgrimes db_watchpoints_inserted = FALSE; 2424Srgrimes} 2434Srgrimes 24412515Sphk#ifdef notused 24512515Sphkstatic boolean_t 246273265Spfgdb_find_watchpoint(vm_map_t map, db_addr_t addr, db_regs_t regs) 2474Srgrimes{ 2484Srgrimes register db_watchpoint_t watch; 2494Srgrimes db_watchpoint_t found = 0; 2504Srgrimes 2514Srgrimes for (watch = db_watchpoint_list; 2524Srgrimes watch != 0; 2534Srgrimes watch = watch->link) 2544Srgrimes if (db_map_equal(watch->map, map)) { 2554Srgrimes if ((watch->loaddr <= addr) && 2564Srgrimes (addr < watch->hiaddr)) 2574Srgrimes return (TRUE); 2584Srgrimes else if ((trunc_page(watch->loaddr) <= addr) && 2594Srgrimes (addr < round_page(watch->hiaddr))) 2604Srgrimes found = watch; 2614Srgrimes } 2624Srgrimes 2634Srgrimes /* 2644Srgrimes * We didn't hit exactly on a watchpoint, but we are 2654Srgrimes * in a protected region. We want to single-step 2664Srgrimes * and then re-protect. 2674Srgrimes */ 2684Srgrimes 2694Srgrimes if (found) { 2704Srgrimes db_watchpoints_inserted = FALSE; 2714Srgrimes db_single_step(regs); 2724Srgrimes } 2734Srgrimes 2744Srgrimes return (FALSE); 2754Srgrimes} 27612515Sphk#endif 27779573Sbsd 27879573Sbsd 27979573Sbsd 28079573Sbsd/* Delete hardware watchpoint */ 28179573Sbsd/*ARGSUSED*/ 28279573Sbsdvoid 283273265Spfgdb_deletehwatch_cmd(db_expr_t addr, boolean_t have_addr, db_expr_t count, 284273265Spfg char *modif) 28579573Sbsd{ 28679573Sbsd int rc; 28779573Sbsd 288273265Spfg if (count < 0) 289273265Spfg count = 4; 29079573Sbsd 29179573Sbsd rc = db_md_clr_watchpoint(addr, count); 29279573Sbsd if (rc < 0) 29379573Sbsd db_printf("hardware watchpoint could not be deleted\n"); 29479573Sbsd} 29579573Sbsd 29679573Sbsd/* Set hardware watchpoint */ 29779573Sbsd/*ARGSUSED*/ 29879573Sbsdvoid 299273265Spfgdb_hwatchpoint_cmd(db_expr_t addr, boolean_t have_addr, db_expr_t count, 300273265Spfg char *modif) 30179573Sbsd{ 30279573Sbsd int rc; 30379573Sbsd 304273265Spfg if (count < 0) 305273265Spfg count = 4; 30679573Sbsd 30779573Sbsd rc = db_md_set_watchpoint(addr, count); 30879573Sbsd if (rc < 0) 30979573Sbsd db_printf("hardware watchpoint could not be set\n"); 31079573Sbsd} 311