db_break.c revision 83506
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 * 2650477Speter * $FreeBSD: head/sys/ddb/db_break.c 83506 2001-09-15 11:06:07Z dfr $ 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> 3712734Sbde 3812662Sdg#include <vm/vm.h> 3912734Sbde#include <vm/vm_kern.h> 4012734Sbde 412056Swollman#include <ddb/ddb.h> 424Srgrimes#include <ddb/db_break.h> 434Srgrimes#include <ddb/db_access.h> 444Srgrimes#include <ddb/db_sym.h> 454Srgrimes 464Srgrimes#define NBREAKPOINTS 100 4712720Sphkstatic struct db_breakpoint db_break_table[NBREAKPOINTS]; 4812515Sphkstatic db_breakpoint_t db_next_free_breakpoint = &db_break_table[0]; 4912515Sphkstatic db_breakpoint_t db_free_breakpoints = 0; 5012515Sphkstatic db_breakpoint_t db_breakpoint_list = 0; 514Srgrimes 5212515Sphkstatic db_breakpoint_t db_breakpoint_alloc __P((void)); 5312515Sphkstatic void db_breakpoint_free __P((db_breakpoint_t bkpt)); 5412515Sphkstatic void db_delete_breakpoint __P((vm_map_t map, db_addr_t addr)); 5512515Sphkstatic db_breakpoint_t db_find_breakpoint __P((vm_map_t map, db_addr_t addr)); 5612515Sphkstatic void db_list_breakpoints __P((void)); 5712515Sphkstatic void db_set_breakpoint __P((vm_map_t map, db_addr_t addr, 5812515Sphk int count)); 5912515Sphk 6012515Sphkstatic db_breakpoint_t 614Srgrimesdb_breakpoint_alloc() 624Srgrimes{ 634Srgrimes register db_breakpoint_t bkpt; 644Srgrimes 654Srgrimes if ((bkpt = db_free_breakpoints) != 0) { 664Srgrimes db_free_breakpoints = bkpt->link; 674Srgrimes return (bkpt); 684Srgrimes } 694Srgrimes if (db_next_free_breakpoint == &db_break_table[NBREAKPOINTS]) { 704Srgrimes db_printf("All breakpoints used.\n"); 714Srgrimes return (0); 724Srgrimes } 734Srgrimes bkpt = db_next_free_breakpoint; 744Srgrimes db_next_free_breakpoint++; 754Srgrimes 764Srgrimes return (bkpt); 774Srgrimes} 784Srgrimes 7912515Sphkstatic void 804Srgrimesdb_breakpoint_free(bkpt) 814Srgrimes register db_breakpoint_t bkpt; 824Srgrimes{ 834Srgrimes bkpt->link = db_free_breakpoints; 844Srgrimes db_free_breakpoints = bkpt; 854Srgrimes} 864Srgrimes 8712515Sphkstatic void 884Srgrimesdb_set_breakpoint(map, addr, count) 894Srgrimes vm_map_t map; 904Srgrimes db_addr_t addr; 914Srgrimes int count; 924Srgrimes{ 934Srgrimes register db_breakpoint_t bkpt; 944Srgrimes 954Srgrimes if (db_find_breakpoint(map, addr)) { 964Srgrimes db_printf("Already set.\n"); 974Srgrimes return; 984Srgrimes } 994Srgrimes 1004Srgrimes bkpt = db_breakpoint_alloc(); 1014Srgrimes if (bkpt == 0) { 1024Srgrimes db_printf("Too many breakpoints.\n"); 1034Srgrimes return; 1044Srgrimes } 1054Srgrimes 1064Srgrimes bkpt->map = map; 1074Srgrimes bkpt->address = addr; 1084Srgrimes bkpt->flags = 0; 1094Srgrimes bkpt->init_count = count; 1104Srgrimes bkpt->count = count; 1114Srgrimes 1124Srgrimes bkpt->link = db_breakpoint_list; 1134Srgrimes db_breakpoint_list = bkpt; 1144Srgrimes} 1154Srgrimes 11612515Sphkstatic void 1174Srgrimesdb_delete_breakpoint(map, addr) 1184Srgrimes vm_map_t map; 1194Srgrimes db_addr_t addr; 1204Srgrimes{ 1214Srgrimes register db_breakpoint_t bkpt; 1224Srgrimes register db_breakpoint_t *prev; 1234Srgrimes 1244Srgrimes for (prev = &db_breakpoint_list; 1254Srgrimes (bkpt = *prev) != 0; 1264Srgrimes prev = &bkpt->link) { 1274Srgrimes if (db_map_equal(bkpt->map, map) && 1284Srgrimes (bkpt->address == addr)) { 1294Srgrimes *prev = bkpt->link; 1304Srgrimes break; 1314Srgrimes } 1324Srgrimes } 1334Srgrimes if (bkpt == 0) { 1344Srgrimes db_printf("Not set.\n"); 1354Srgrimes return; 1364Srgrimes } 1374Srgrimes 1384Srgrimes db_breakpoint_free(bkpt); 1394Srgrimes} 1404Srgrimes 14112515Sphkstatic db_breakpoint_t 1424Srgrimesdb_find_breakpoint(map, addr) 1434Srgrimes vm_map_t map; 1444Srgrimes db_addr_t addr; 1454Srgrimes{ 1464Srgrimes register db_breakpoint_t bkpt; 1474Srgrimes 1484Srgrimes for (bkpt = db_breakpoint_list; 1494Srgrimes bkpt != 0; 1504Srgrimes bkpt = bkpt->link) 1514Srgrimes { 1524Srgrimes if (db_map_equal(bkpt->map, map) && 1534Srgrimes (bkpt->address == addr)) 1544Srgrimes return (bkpt); 1554Srgrimes } 1564Srgrimes return (0); 1574Srgrimes} 1584Srgrimes 1594Srgrimesdb_breakpoint_t 1604Srgrimesdb_find_breakpoint_here(addr) 1614Srgrimes db_addr_t addr; 1624Srgrimes{ 1634Srgrimes return db_find_breakpoint(db_map_addr(addr), addr); 1644Srgrimes} 1654Srgrimes 16612515Sphkstatic boolean_t db_breakpoints_inserted = TRUE; 1674Srgrimes 16883506Sdfr#ifndef BKPT_WRITE 16983506Sdfr#define BKPT_WRITE(addr, storage) \ 17083506Sdfrdo { \ 17183506Sdfr *storage = db_get_value(addr, BKPT_SIZE, FALSE); \ 17283506Sdfr db_put_value(addr, BKPT_SIZE, BKPT_SET(*storage)); \ 17383506Sdfr} while (0) 17483506Sdfr#endif 17583506Sdfr 17683506Sdfr#ifndef BKPT_CLEAR 17783506Sdfr#define BKPT_CLEAR(addr, storage) \ 17883506Sdfr db_put_value(addr, BKPT_SIZE, *storage) 17983506Sdfr#endif 18083506Sdfr 1814Srgrimesvoid 1824Srgrimesdb_set_breakpoints() 1834Srgrimes{ 1844Srgrimes register db_breakpoint_t bkpt; 1854Srgrimes 1864Srgrimes if (!db_breakpoints_inserted) { 1874Srgrimes 18883506Sdfr for (bkpt = db_breakpoint_list; 18983506Sdfr bkpt != 0; 19083506Sdfr bkpt = bkpt->link) 19183506Sdfr if (db_map_current(bkpt->map)) { 19283506Sdfr BKPT_WRITE(bkpt->address, &bkpt->bkpt_inst); 19383506Sdfr } 19483506Sdfr db_breakpoints_inserted = TRUE; 1954Srgrimes } 1964Srgrimes} 1974Srgrimes 1984Srgrimesvoid 1994Srgrimesdb_clear_breakpoints() 2004Srgrimes{ 2014Srgrimes register db_breakpoint_t bkpt; 2024Srgrimes 2034Srgrimes if (db_breakpoints_inserted) { 2044Srgrimes 20583506Sdfr for (bkpt = db_breakpoint_list; 20683506Sdfr bkpt != 0; 20783506Sdfr bkpt = bkpt->link) 20883506Sdfr if (db_map_current(bkpt->map)) { 20983506Sdfr BKPT_CLEAR(bkpt->address, &bkpt->bkpt_inst); 21083506Sdfr } 21183506Sdfr db_breakpoints_inserted = FALSE; 2124Srgrimes } 2134Srgrimes} 2144Srgrimes 21536735Sdfr#ifdef SOFTWARE_SSTEP 2164Srgrimes/* 2174Srgrimes * Set a temporary breakpoint. 2184Srgrimes * The instruction is changed immediately, 2194Srgrimes * so the breakpoint does not have to be on the breakpoint list. 2204Srgrimes */ 22136735Sdfrdb_breakpoint_t 2224Srgrimesdb_set_temp_breakpoint(addr) 2234Srgrimes db_addr_t addr; 2244Srgrimes{ 2254Srgrimes register db_breakpoint_t bkpt; 2264Srgrimes 2274Srgrimes bkpt = db_breakpoint_alloc(); 2284Srgrimes if (bkpt == 0) { 2294Srgrimes db_printf("Too many breakpoints.\n"); 2304Srgrimes return 0; 2314Srgrimes } 2324Srgrimes 2334Srgrimes bkpt->map = NULL; 2344Srgrimes bkpt->address = addr; 2354Srgrimes bkpt->flags = BKPT_TEMP; 2364Srgrimes bkpt->init_count = 1; 2374Srgrimes bkpt->count = 1; 2384Srgrimes 23983506Sdfr BKPT_WRITE(bkpt->address, &bkpt->bkpt_inst); 2404Srgrimes return bkpt; 2414Srgrimes} 2424Srgrimes 24336735Sdfrvoid 2444Srgrimesdb_delete_temp_breakpoint(bkpt) 2454Srgrimes db_breakpoint_t bkpt; 2464Srgrimes{ 24783506Sdfr BKPT_CLEAR(bkpt->address, &bkpt->bkpt_inst); 2484Srgrimes db_breakpoint_free(bkpt); 2494Srgrimes} 25036745Sbde#endif /* SOFTWARE_SSTEP */ 25136735Sdfr 2524Srgrimes/* 2534Srgrimes * List breakpoints. 2544Srgrimes */ 25512515Sphkstatic void 2564Srgrimesdb_list_breakpoints() 2574Srgrimes{ 2584Srgrimes register db_breakpoint_t bkpt; 2594Srgrimes 2604Srgrimes if (db_breakpoint_list == 0) { 2614Srgrimes db_printf("No breakpoints set\n"); 2624Srgrimes return; 2634Srgrimes } 2644Srgrimes 2654Srgrimes db_printf(" Map Count Address\n"); 2664Srgrimes for (bkpt = db_breakpoint_list; 2674Srgrimes bkpt != 0; 26837497Sbde bkpt = bkpt->link) { 26937497Sbde db_printf("%s%8p %5d ", 2704Srgrimes db_map_current(bkpt->map) ? "*" : " ", 27137497Sbde (void *)bkpt->map, bkpt->init_count); 2724Srgrimes db_printsym(bkpt->address, DB_STGY_PROC); 2734Srgrimes db_printf("\n"); 2744Srgrimes } 2754Srgrimes} 2764Srgrimes 2774Srgrimes/* Delete breakpoint */ 2784Srgrimes/*ARGSUSED*/ 2794Srgrimesvoid 2804Srgrimesdb_delete_cmd(addr, have_addr, count, modif) 2814Srgrimes db_expr_t addr; 28212473Sbde boolean_t have_addr; 2834Srgrimes db_expr_t count; 2844Srgrimes char * modif; 2854Srgrimes{ 2864Srgrimes db_delete_breakpoint(db_map_addr(addr), (db_addr_t)addr); 2874Srgrimes} 2884Srgrimes 2894Srgrimes/* Set breakpoint with skip count */ 2904Srgrimes/*ARGSUSED*/ 2914Srgrimesvoid 2924Srgrimesdb_breakpoint_cmd(addr, have_addr, count, modif) 2934Srgrimes db_expr_t addr; 29412473Sbde boolean_t have_addr; 2954Srgrimes db_expr_t count; 2964Srgrimes char * modif; 2974Srgrimes{ 2984Srgrimes if (count == -1) 2994Srgrimes count = 1; 3004Srgrimes 3014Srgrimes db_set_breakpoint(db_map_addr(addr), (db_addr_t)addr, count); 3024Srgrimes} 3034Srgrimes 3044Srgrimes/* list breakpoints */ 3054Srgrimesvoid 30612473Sbdedb_listbreak_cmd(dummy1, dummy2, dummy3, dummy4) 30712473Sbde db_expr_t dummy1; 30812473Sbde boolean_t dummy2; 30912473Sbde db_expr_t dummy3; 31012473Sbde char * dummy4; 3114Srgrimes{ 3124Srgrimes db_list_breakpoints(); 3134Srgrimes} 3144Srgrimes 3154Srgrimes/* 3164Srgrimes * We want ddb to be usable before most of the kernel has been 3174Srgrimes * initialized. In particular, current_thread() or kernel_map 3184Srgrimes * (or both) may be null. 3194Srgrimes */ 3204Srgrimes 3214Srgrimesboolean_t 3224Srgrimesdb_map_equal(map1, map2) 3234Srgrimes vm_map_t map1, map2; 3244Srgrimes{ 3254Srgrimes return ((map1 == map2) || 3264Srgrimes ((map1 == NULL) && (map2 == kernel_map)) || 3274Srgrimes ((map1 == kernel_map) && (map2 == NULL))); 3284Srgrimes} 3294Srgrimes 3304Srgrimesboolean_t 3314Srgrimesdb_map_current(map) 3324Srgrimes vm_map_t map; 3334Srgrimes{ 3344Srgrimes#if 0 3354Srgrimes thread_t thread; 3364Srgrimes 3374Srgrimes return ((map == NULL) || 3384Srgrimes (map == kernel_map) || 3394Srgrimes (((thread = current_thread()) != NULL) && 3404Srgrimes (map == thread->task->map))); 3414Srgrimes#else 3424Srgrimes return (1); 3434Srgrimes#endif 3444Srgrimes} 3454Srgrimes 3464Srgrimesvm_map_t 3474Srgrimesdb_map_addr(addr) 3484Srgrimes vm_offset_t addr; 3494Srgrimes{ 3504Srgrimes#if 0 3514Srgrimes thread_t thread; 3524Srgrimes 3534Srgrimes /* 3544Srgrimes * We want to return kernel_map for all 3554Srgrimes * non-user addresses, even when debugging 3564Srgrimes * kernel tasks with their own maps. 3574Srgrimes */ 3584Srgrimes 3594Srgrimes if ((VM_MIN_ADDRESS <= addr) && 3604Srgrimes (addr < VM_MAX_ADDRESS) && 3614Srgrimes ((thread = current_thread()) != NULL)) 3624Srgrimes return thread->task->map; 3634Srgrimes else 3644Srgrimes#endif 3654Srgrimes return kernel_map; 3664Srgrimes} 367