db_break.c revision 8876
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 * 268876Srgrimes * $Id: db_break.c,v 1.5 1994/08/18 22:34:19 wollman Exp $ 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> 372056Swollman#include <sys/systm.h> 382056Swollman#include <sys/proc.h> 392056Swollman#include <ddb/ddb.h> 404Srgrimes 414Srgrimes#include <ddb/db_lex.h> 424Srgrimes#include <ddb/db_break.h> 434Srgrimes#include <ddb/db_access.h> 444Srgrimes#include <ddb/db_sym.h> 454Srgrimes#include <ddb/db_break.h> 464Srgrimes 474Srgrimes#define NBREAKPOINTS 100 484Srgrimesstruct db_breakpoint db_break_table[NBREAKPOINTS]; 494Srgrimesdb_breakpoint_t db_next_free_breakpoint = &db_break_table[0]; 504Srgrimesdb_breakpoint_t db_free_breakpoints = 0; 514Srgrimesdb_breakpoint_t db_breakpoint_list = 0; 524Srgrimes 534Srgrimesdb_breakpoint_t 544Srgrimesdb_breakpoint_alloc() 554Srgrimes{ 564Srgrimes register db_breakpoint_t bkpt; 574Srgrimes 584Srgrimes if ((bkpt = db_free_breakpoints) != 0) { 594Srgrimes db_free_breakpoints = bkpt->link; 604Srgrimes return (bkpt); 614Srgrimes } 624Srgrimes if (db_next_free_breakpoint == &db_break_table[NBREAKPOINTS]) { 634Srgrimes db_printf("All breakpoints used.\n"); 644Srgrimes return (0); 654Srgrimes } 664Srgrimes bkpt = db_next_free_breakpoint; 674Srgrimes db_next_free_breakpoint++; 684Srgrimes 694Srgrimes return (bkpt); 704Srgrimes} 714Srgrimes 724Srgrimesvoid 734Srgrimesdb_breakpoint_free(bkpt) 744Srgrimes register db_breakpoint_t bkpt; 754Srgrimes{ 764Srgrimes bkpt->link = db_free_breakpoints; 774Srgrimes db_free_breakpoints = bkpt; 784Srgrimes} 794Srgrimes 804Srgrimesvoid 814Srgrimesdb_set_breakpoint(map, addr, count) 824Srgrimes vm_map_t map; 834Srgrimes db_addr_t addr; 844Srgrimes int count; 854Srgrimes{ 864Srgrimes register db_breakpoint_t bkpt; 874Srgrimes 884Srgrimes if (db_find_breakpoint(map, addr)) { 894Srgrimes db_printf("Already set.\n"); 904Srgrimes return; 914Srgrimes } 924Srgrimes 934Srgrimes bkpt = db_breakpoint_alloc(); 944Srgrimes if (bkpt == 0) { 954Srgrimes db_printf("Too many breakpoints.\n"); 964Srgrimes return; 974Srgrimes } 984Srgrimes 994Srgrimes bkpt->map = map; 1004Srgrimes bkpt->address = addr; 1014Srgrimes bkpt->flags = 0; 1024Srgrimes bkpt->init_count = count; 1034Srgrimes bkpt->count = count; 1044Srgrimes 1054Srgrimes bkpt->link = db_breakpoint_list; 1064Srgrimes db_breakpoint_list = bkpt; 1074Srgrimes} 1084Srgrimes 1094Srgrimesvoid 1104Srgrimesdb_delete_breakpoint(map, addr) 1114Srgrimes vm_map_t map; 1124Srgrimes db_addr_t addr; 1134Srgrimes{ 1144Srgrimes register db_breakpoint_t bkpt; 1154Srgrimes register db_breakpoint_t *prev; 1164Srgrimes 1174Srgrimes for (prev = &db_breakpoint_list; 1184Srgrimes (bkpt = *prev) != 0; 1194Srgrimes prev = &bkpt->link) { 1204Srgrimes if (db_map_equal(bkpt->map, map) && 1214Srgrimes (bkpt->address == addr)) { 1224Srgrimes *prev = bkpt->link; 1234Srgrimes break; 1244Srgrimes } 1254Srgrimes } 1264Srgrimes if (bkpt == 0) { 1274Srgrimes db_printf("Not set.\n"); 1284Srgrimes return; 1294Srgrimes } 1304Srgrimes 1314Srgrimes db_breakpoint_free(bkpt); 1324Srgrimes} 1334Srgrimes 1344Srgrimesdb_breakpoint_t 1354Srgrimesdb_find_breakpoint(map, addr) 1364Srgrimes vm_map_t map; 1374Srgrimes 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 1534Srgrimesdb_find_breakpoint_here(addr) 1544Srgrimes db_addr_t addr; 1554Srgrimes{ 1564Srgrimes return db_find_breakpoint(db_map_addr(addr), addr); 1574Srgrimes} 1584Srgrimes 1594Srgrimesboolean_t db_breakpoints_inserted = TRUE; 1604Srgrimes 1614Srgrimesvoid 1624Srgrimesdb_set_breakpoints() 1634Srgrimes{ 1644Srgrimes register db_breakpoint_t bkpt; 1654Srgrimes 1664Srgrimes if (!db_breakpoints_inserted) { 1674Srgrimes 1684Srgrimes for (bkpt = db_breakpoint_list; 1694Srgrimes bkpt != 0; 1704Srgrimes bkpt = bkpt->link) 1714Srgrimes if (db_map_current(bkpt->map)) { 1724Srgrimes bkpt->bkpt_inst = db_get_value(bkpt->address, 1734Srgrimes BKPT_SIZE, 1744Srgrimes FALSE); 1754Srgrimes db_put_value(bkpt->address, 1764Srgrimes BKPT_SIZE, 1774Srgrimes BKPT_SET(bkpt->bkpt_inst)); 1784Srgrimes } 1794Srgrimes db_breakpoints_inserted = TRUE; 1804Srgrimes } 1814Srgrimes} 1824Srgrimes 1834Srgrimesvoid 1844Srgrimesdb_clear_breakpoints() 1854Srgrimes{ 1864Srgrimes register db_breakpoint_t bkpt; 1874Srgrimes 1884Srgrimes if (db_breakpoints_inserted) { 1894Srgrimes 1904Srgrimes for (bkpt = db_breakpoint_list; 1914Srgrimes bkpt != 0; 1924Srgrimes bkpt = bkpt->link) 1934Srgrimes if (db_map_current(bkpt->map)) { 1944Srgrimes db_put_value(bkpt->address, BKPT_SIZE, bkpt->bkpt_inst); 1954Srgrimes } 1964Srgrimes db_breakpoints_inserted = FALSE; 1974Srgrimes } 1984Srgrimes} 1994Srgrimes 2004Srgrimes/* 2014Srgrimes * Set a temporary breakpoint. 2024Srgrimes * The instruction is changed immediately, 2034Srgrimes * so the breakpoint does not have to be on the breakpoint list. 2044Srgrimes */ 2054Srgrimesdb_breakpoint_t 2064Srgrimesdb_set_temp_breakpoint(addr) 2074Srgrimes db_addr_t addr; 2084Srgrimes{ 2094Srgrimes register db_breakpoint_t bkpt; 2104Srgrimes 2114Srgrimes bkpt = db_breakpoint_alloc(); 2124Srgrimes if (bkpt == 0) { 2134Srgrimes db_printf("Too many breakpoints.\n"); 2144Srgrimes return 0; 2154Srgrimes } 2164Srgrimes 2174Srgrimes bkpt->map = NULL; 2184Srgrimes bkpt->address = addr; 2194Srgrimes bkpt->flags = BKPT_TEMP; 2204Srgrimes bkpt->init_count = 1; 2214Srgrimes bkpt->count = 1; 2224Srgrimes 2234Srgrimes bkpt->bkpt_inst = db_get_value(bkpt->address, BKPT_SIZE, FALSE); 2244Srgrimes db_put_value(bkpt->address, BKPT_SIZE, BKPT_SET(bkpt->bkpt_inst)); 2254Srgrimes return bkpt; 2264Srgrimes} 2274Srgrimes 2284Srgrimesvoid 2294Srgrimesdb_delete_temp_breakpoint(bkpt) 2304Srgrimes db_breakpoint_t bkpt; 2314Srgrimes{ 2324Srgrimes db_put_value(bkpt->address, BKPT_SIZE, bkpt->bkpt_inst); 2334Srgrimes db_breakpoint_free(bkpt); 2344Srgrimes} 2354Srgrimes 2364Srgrimes/* 2374Srgrimes * List breakpoints. 2384Srgrimes */ 2394Srgrimesvoid 2404Srgrimesdb_list_breakpoints() 2414Srgrimes{ 2424Srgrimes register db_breakpoint_t bkpt; 2434Srgrimes 2444Srgrimes if (db_breakpoint_list == 0) { 2454Srgrimes db_printf("No breakpoints set\n"); 2464Srgrimes return; 2474Srgrimes } 2484Srgrimes 2494Srgrimes db_printf(" Map Count Address\n"); 2504Srgrimes for (bkpt = db_breakpoint_list; 2514Srgrimes bkpt != 0; 2524Srgrimes bkpt = bkpt->link) 2534Srgrimes { 2544Srgrimes db_printf("%s%8x %5d ", 2554Srgrimes db_map_current(bkpt->map) ? "*" : " ", 2564Srgrimes bkpt->map, bkpt->init_count); 2574Srgrimes db_printsym(bkpt->address, DB_STGY_PROC); 2584Srgrimes db_printf("\n"); 2594Srgrimes } 2604Srgrimes} 2614Srgrimes 2624Srgrimes/* Delete breakpoint */ 2634Srgrimes/*ARGSUSED*/ 2644Srgrimesvoid 2654Srgrimesdb_delete_cmd(addr, have_addr, count, modif) 2664Srgrimes db_expr_t addr; 2674Srgrimes int have_addr; 2684Srgrimes db_expr_t count; 2694Srgrimes char * modif; 2704Srgrimes{ 2714Srgrimes db_delete_breakpoint(db_map_addr(addr), (db_addr_t)addr); 2724Srgrimes} 2734Srgrimes 2744Srgrimes/* Set breakpoint with skip count */ 2754Srgrimes/*ARGSUSED*/ 2764Srgrimesvoid 2774Srgrimesdb_breakpoint_cmd(addr, have_addr, count, modif) 2784Srgrimes db_expr_t addr; 2794Srgrimes int have_addr; 2804Srgrimes db_expr_t count; 2814Srgrimes char * modif; 2824Srgrimes{ 2834Srgrimes if (count == -1) 2844Srgrimes count = 1; 2854Srgrimes 2864Srgrimes db_set_breakpoint(db_map_addr(addr), (db_addr_t)addr, count); 2874Srgrimes} 2884Srgrimes 2894Srgrimes/* list breakpoints */ 2904Srgrimesvoid 291798Swollmandb_listbreak_cmd(db_expr_t dummy1, int dummy2, db_expr_t dummy3, char *dummy4) 2924Srgrimes{ 2934Srgrimes db_list_breakpoints(); 2944Srgrimes} 2954Srgrimes 2964Srgrimes#include <vm/vm_kern.h> 2974Srgrimes 2984Srgrimes/* 2994Srgrimes * We want ddb to be usable before most of the kernel has been 3004Srgrimes * initialized. In particular, current_thread() or kernel_map 3014Srgrimes * (or both) may be null. 3024Srgrimes */ 3034Srgrimes 3044Srgrimesboolean_t 3054Srgrimesdb_map_equal(map1, map2) 3064Srgrimes vm_map_t map1, map2; 3074Srgrimes{ 3084Srgrimes return ((map1 == map2) || 3094Srgrimes ((map1 == NULL) && (map2 == kernel_map)) || 3104Srgrimes ((map1 == kernel_map) && (map2 == NULL))); 3114Srgrimes} 3124Srgrimes 3134Srgrimesboolean_t 3144Srgrimesdb_map_current(map) 3154Srgrimes vm_map_t map; 3164Srgrimes{ 3174Srgrimes#if 0 3184Srgrimes thread_t thread; 3194Srgrimes 3204Srgrimes return ((map == NULL) || 3214Srgrimes (map == kernel_map) || 3224Srgrimes (((thread = current_thread()) != NULL) && 3234Srgrimes (map == thread->task->map))); 3244Srgrimes#else 3254Srgrimes return (1); 3264Srgrimes#endif 3274Srgrimes} 3284Srgrimes 3294Srgrimesvm_map_t 3304Srgrimesdb_map_addr(addr) 3314Srgrimes vm_offset_t addr; 3324Srgrimes{ 3334Srgrimes#if 0 3344Srgrimes thread_t thread; 3354Srgrimes 3364Srgrimes /* 3374Srgrimes * We want to return kernel_map for all 3384Srgrimes * non-user addresses, even when debugging 3394Srgrimes * kernel tasks with their own maps. 3404Srgrimes */ 3414Srgrimes 3424Srgrimes if ((VM_MIN_ADDRESS <= addr) && 3434Srgrimes (addr < VM_MAX_ADDRESS) && 3444Srgrimes ((thread = current_thread()) != NULL)) 3454Srgrimes return thread->task->map; 3464Srgrimes else 3474Srgrimes#endif 3484Srgrimes return kernel_map; 3494Srgrimes} 350