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/* 284Srgrimes * Author: David B. Golub, Carnegie Mellon University 294Srgrimes * Date: 7/90 304Srgrimes */ 314Srgrimes/* 324Srgrimes * Breakpoints. 334Srgrimes */ 34116176Sobrien 35116176Sobrien#include <sys/cdefs.h> 36116176Sobrien__FBSDID("$FreeBSD: releng/11.0/sys/ddb/db_break.c 283248 2015-05-21 15:16:18Z pfg $"); 37116176Sobrien 382056Swollman#include <sys/param.h> 3912734Sbde 4012662Sdg#include <vm/vm.h> 4112734Sbde#include <vm/vm_kern.h> 4212734Sbde 432056Swollman#include <ddb/ddb.h> 444Srgrimes#include <ddb/db_break.h> 454Srgrimes#include <ddb/db_access.h> 464Srgrimes#include <ddb/db_sym.h> 474Srgrimes 484Srgrimes#define NBREAKPOINTS 100 4912720Sphkstatic struct db_breakpoint db_break_table[NBREAKPOINTS]; 5012515Sphkstatic db_breakpoint_t db_next_free_breakpoint = &db_break_table[0]; 5112515Sphkstatic db_breakpoint_t db_free_breakpoints = 0; 5212515Sphkstatic db_breakpoint_t db_breakpoint_list = 0; 534Srgrimes 5492756Salfredstatic db_breakpoint_t db_breakpoint_alloc(void); 5592756Salfredstatic void db_breakpoint_free(db_breakpoint_t bkpt); 5692756Salfredstatic void db_delete_breakpoint(vm_map_t map, db_addr_t addr); 5792756Salfredstatic db_breakpoint_t db_find_breakpoint(vm_map_t map, db_addr_t addr); 5892756Salfredstatic void db_list_breakpoints(void); 5992756Salfredstatic void db_set_breakpoint(vm_map_t map, db_addr_t addr, int count); 6012515Sphk 6112515Sphkstatic db_breakpoint_t 62273006Spfgdb_breakpoint_alloc(void) 634Srgrimes{ 644Srgrimes register db_breakpoint_t bkpt; 654Srgrimes 664Srgrimes if ((bkpt = db_free_breakpoints) != 0) { 674Srgrimes db_free_breakpoints = bkpt->link; 684Srgrimes return (bkpt); 694Srgrimes } 704Srgrimes if (db_next_free_breakpoint == &db_break_table[NBREAKPOINTS]) { 714Srgrimes db_printf("All breakpoints used.\n"); 724Srgrimes return (0); 734Srgrimes } 744Srgrimes bkpt = db_next_free_breakpoint; 754Srgrimes db_next_free_breakpoint++; 764Srgrimes 774Srgrimes return (bkpt); 784Srgrimes} 794Srgrimes 8012515Sphkstatic void 81273006Spfgdb_breakpoint_free(db_breakpoint_t bkpt) 824Srgrimes{ 834Srgrimes bkpt->link = db_free_breakpoints; 844Srgrimes db_free_breakpoints = bkpt; 854Srgrimes} 864Srgrimes 8712515Sphkstatic void 88273006Spfgdb_set_breakpoint(vm_map_t map, db_addr_t addr, int count) 894Srgrimes{ 904Srgrimes register db_breakpoint_t bkpt; 914Srgrimes 924Srgrimes if (db_find_breakpoint(map, addr)) { 934Srgrimes db_printf("Already set.\n"); 944Srgrimes return; 954Srgrimes } 964Srgrimes 974Srgrimes bkpt = db_breakpoint_alloc(); 984Srgrimes if (bkpt == 0) { 994Srgrimes db_printf("Too many breakpoints.\n"); 1004Srgrimes return; 1014Srgrimes } 1024Srgrimes 1034Srgrimes bkpt->map = map; 1044Srgrimes bkpt->address = addr; 1054Srgrimes bkpt->flags = 0; 1064Srgrimes bkpt->init_count = count; 1074Srgrimes bkpt->count = count; 1084Srgrimes 1094Srgrimes bkpt->link = db_breakpoint_list; 1104Srgrimes db_breakpoint_list = bkpt; 1114Srgrimes} 1124Srgrimes 11312515Sphkstatic void 114273006Spfgdb_delete_breakpoint(vm_map_t map, db_addr_t addr) 1154Srgrimes{ 1164Srgrimes register db_breakpoint_t bkpt; 1174Srgrimes register db_breakpoint_t *prev; 1184Srgrimes 1194Srgrimes for (prev = &db_breakpoint_list; 1204Srgrimes (bkpt = *prev) != 0; 1214Srgrimes prev = &bkpt->link) { 1224Srgrimes if (db_map_equal(bkpt->map, map) && 1234Srgrimes (bkpt->address == addr)) { 1244Srgrimes *prev = bkpt->link; 1254Srgrimes break; 1264Srgrimes } 1274Srgrimes } 1284Srgrimes if (bkpt == 0) { 1294Srgrimes db_printf("Not set.\n"); 1304Srgrimes return; 1314Srgrimes } 1324Srgrimes 1334Srgrimes db_breakpoint_free(bkpt); 1344Srgrimes} 1354Srgrimes 13612515Sphkstatic db_breakpoint_t 137273006Spfgdb_find_breakpoint(vm_map_t map, db_addr_t addr) 1384Srgrimes{ 1394Srgrimes register db_breakpoint_t bkpt; 1404Srgrimes 1414Srgrimes for (bkpt = db_breakpoint_list; 1424Srgrimes bkpt != 0; 1434Srgrimes bkpt = bkpt->link) 1444Srgrimes { 1454Srgrimes if (db_map_equal(bkpt->map, map) && 1464Srgrimes (bkpt->address == addr)) 1474Srgrimes return (bkpt); 1484Srgrimes } 1494Srgrimes return (0); 1504Srgrimes} 1514Srgrimes 1524Srgrimesdb_breakpoint_t 153273006Spfgdb_find_breakpoint_here(db_addr_t addr) 1544Srgrimes{ 155272958Spfg return db_find_breakpoint(db_map_addr(addr), addr); 1564Srgrimes} 1574Srgrimes 158283248Spfgstatic bool db_breakpoints_inserted = true; 1594Srgrimes 16083506Sdfr#ifndef BKPT_WRITE 161272958Spfg#define BKPT_WRITE(addr, storage) \ 16283506Sdfrdo { \ 163283088Spfg *storage = db_get_value(addr, BKPT_SIZE, false); \ 16483506Sdfr db_put_value(addr, BKPT_SIZE, BKPT_SET(*storage)); \ 16583506Sdfr} while (0) 16683506Sdfr#endif 16783506Sdfr 16883506Sdfr#ifndef BKPT_CLEAR 169272958Spfg#define BKPT_CLEAR(addr, storage) \ 17083506Sdfr db_put_value(addr, BKPT_SIZE, *storage) 17183506Sdfr#endif 17283506Sdfr 1734Srgrimesvoid 174273006Spfgdb_set_breakpoints(void) 1754Srgrimes{ 1764Srgrimes register db_breakpoint_t bkpt; 1774Srgrimes 1784Srgrimes if (!db_breakpoints_inserted) { 1794Srgrimes 18083506Sdfr for (bkpt = db_breakpoint_list; 18183506Sdfr bkpt != 0; 18283506Sdfr bkpt = bkpt->link) 18383506Sdfr if (db_map_current(bkpt->map)) { 18483506Sdfr BKPT_WRITE(bkpt->address, &bkpt->bkpt_inst); 18583506Sdfr } 186283088Spfg db_breakpoints_inserted = true; 1874Srgrimes } 1884Srgrimes} 1894Srgrimes 1904Srgrimesvoid 191273006Spfgdb_clear_breakpoints(void) 1924Srgrimes{ 1934Srgrimes register db_breakpoint_t bkpt; 1944Srgrimes 1954Srgrimes if (db_breakpoints_inserted) { 1964Srgrimes 19783506Sdfr for (bkpt = db_breakpoint_list; 19883506Sdfr bkpt != 0; 19983506Sdfr bkpt = bkpt->link) 20083506Sdfr if (db_map_current(bkpt->map)) { 20183506Sdfr BKPT_CLEAR(bkpt->address, &bkpt->bkpt_inst); 20283506Sdfr } 203283088Spfg db_breakpoints_inserted = false; 2044Srgrimes } 2054Srgrimes} 2064Srgrimes 20736735Sdfr#ifdef SOFTWARE_SSTEP 2084Srgrimes/* 2094Srgrimes * Set a temporary breakpoint. 2104Srgrimes * The instruction is changed immediately, 2114Srgrimes * so the breakpoint does not have to be on the breakpoint list. 2124Srgrimes */ 21336735Sdfrdb_breakpoint_t 214273006Spfgdb_set_temp_breakpoint(db_addr_t addr) 2154Srgrimes{ 2164Srgrimes register db_breakpoint_t bkpt; 2174Srgrimes 2184Srgrimes bkpt = db_breakpoint_alloc(); 2194Srgrimes if (bkpt == 0) { 2204Srgrimes db_printf("Too many breakpoints.\n"); 2214Srgrimes return 0; 2224Srgrimes } 2234Srgrimes 2244Srgrimes bkpt->map = NULL; 2254Srgrimes bkpt->address = addr; 2264Srgrimes bkpt->flags = BKPT_TEMP; 2274Srgrimes bkpt->init_count = 1; 2284Srgrimes bkpt->count = 1; 2294Srgrimes 23083506Sdfr BKPT_WRITE(bkpt->address, &bkpt->bkpt_inst); 2314Srgrimes return bkpt; 2324Srgrimes} 2334Srgrimes 23436735Sdfrvoid 235273006Spfgdb_delete_temp_breakpoint(db_breakpoint_t bkpt) 2364Srgrimes{ 23783506Sdfr BKPT_CLEAR(bkpt->address, &bkpt->bkpt_inst); 2384Srgrimes db_breakpoint_free(bkpt); 2394Srgrimes} 24036745Sbde#endif /* SOFTWARE_SSTEP */ 24136735Sdfr 2424Srgrimes/* 2434Srgrimes * List breakpoints. 2444Srgrimes */ 24512515Sphkstatic void 246273006Spfgdb_list_breakpoints(void) 2474Srgrimes{ 2484Srgrimes register db_breakpoint_t bkpt; 2494Srgrimes 2504Srgrimes if (db_breakpoint_list == 0) { 2514Srgrimes db_printf("No breakpoints set\n"); 2524Srgrimes return; 2534Srgrimes } 2544Srgrimes 2554Srgrimes db_printf(" Map Count Address\n"); 2564Srgrimes for (bkpt = db_breakpoint_list; 2574Srgrimes bkpt != 0; 25837497Sbde bkpt = bkpt->link) { 25937497Sbde db_printf("%s%8p %5d ", 2604Srgrimes db_map_current(bkpt->map) ? "*" : " ", 26137497Sbde (void *)bkpt->map, bkpt->init_count); 2624Srgrimes db_printsym(bkpt->address, DB_STGY_PROC); 2634Srgrimes db_printf("\n"); 2644Srgrimes } 2654Srgrimes} 2664Srgrimes 2674Srgrimes/* Delete breakpoint */ 2684Srgrimes/*ARGSUSED*/ 2694Srgrimesvoid 270283248Spfgdb_delete_cmd(db_expr_t addr, bool have_addr, db_expr_t count, char *modif) 2714Srgrimes{ 2724Srgrimes db_delete_breakpoint(db_map_addr(addr), (db_addr_t)addr); 2734Srgrimes} 2744Srgrimes 2754Srgrimes/* Set breakpoint with skip count */ 2764Srgrimes/*ARGSUSED*/ 2774Srgrimesvoid 278283248Spfgdb_breakpoint_cmd(db_expr_t addr, bool have_addr, db_expr_t count, char *modif) 2794Srgrimes{ 2804Srgrimes if (count == -1) 2814Srgrimes count = 1; 2824Srgrimes 2834Srgrimes db_set_breakpoint(db_map_addr(addr), (db_addr_t)addr, count); 2844Srgrimes} 2854Srgrimes 2864Srgrimes/* list breakpoints */ 2874Srgrimesvoid 288283248Spfgdb_listbreak_cmd(db_expr_t dummy1, bool dummy2, db_expr_t dummy3, char *dummy4) 2894Srgrimes{ 2904Srgrimes db_list_breakpoints(); 2914Srgrimes} 2924Srgrimes 2934Srgrimes/* 2944Srgrimes * We want ddb to be usable before most of the kernel has been 2954Srgrimes * initialized. In particular, current_thread() or kernel_map 2964Srgrimes * (or both) may be null. 2974Srgrimes */ 2984Srgrimes 299283248Spfgbool 300273006Spfgdb_map_equal(vm_map_t map1, vm_map_t map2) 3014Srgrimes{ 3024Srgrimes return ((map1 == map2) || 3034Srgrimes ((map1 == NULL) && (map2 == kernel_map)) || 3044Srgrimes ((map1 == kernel_map) && (map2 == NULL))); 3054Srgrimes} 3064Srgrimes 307283248Spfgbool 308273006Spfgdb_map_current(vm_map_t map) 3094Srgrimes{ 3104Srgrimes#if 0 3114Srgrimes thread_t thread; 3124Srgrimes 3134Srgrimes return ((map == NULL) || 3144Srgrimes (map == kernel_map) || 3154Srgrimes (((thread = current_thread()) != NULL) && 3164Srgrimes (map == thread->task->map))); 3174Srgrimes#else 318283248Spfg return (true); 3194Srgrimes#endif 3204Srgrimes} 3214Srgrimes 3224Srgrimesvm_map_t 323273006Spfgdb_map_addr(vm_offset_t addr) 3244Srgrimes{ 3254Srgrimes#if 0 3264Srgrimes thread_t thread; 3274Srgrimes 3284Srgrimes /* 3294Srgrimes * We want to return kernel_map for all 3304Srgrimes * non-user addresses, even when debugging 3314Srgrimes * kernel tasks with their own maps. 3324Srgrimes */ 3334Srgrimes 3344Srgrimes if ((VM_MIN_ADDRESS <= addr) && 3354Srgrimes (addr < VM_MAX_ADDRESS) && 3364Srgrimes ((thread = current_thread()) != NULL)) 3374Srgrimes return thread->task->map; 3384Srgrimes else 3394Srgrimes#endif 3404Srgrimes return kernel_map; 3414Srgrimes} 342