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