db_break.c revision 92756
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 92756 2002-03-20 05:14:42Z alfred $ 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 5292756Salfredstatic db_breakpoint_t db_breakpoint_alloc(void); 5392756Salfredstatic void db_breakpoint_free(db_breakpoint_t bkpt); 5492756Salfredstatic void db_delete_breakpoint(vm_map_t map, db_addr_t addr); 5592756Salfredstatic db_breakpoint_t db_find_breakpoint(vm_map_t map, db_addr_t addr); 5692756Salfredstatic void db_list_breakpoints(void); 5792756Salfredstatic void db_set_breakpoint(vm_map_t map, db_addr_t addr, int count); 5812515Sphk 5912515Sphkstatic db_breakpoint_t 604Srgrimesdb_breakpoint_alloc() 614Srgrimes{ 624Srgrimes register db_breakpoint_t bkpt; 634Srgrimes 644Srgrimes if ((bkpt = db_free_breakpoints) != 0) { 654Srgrimes db_free_breakpoints = bkpt->link; 664Srgrimes return (bkpt); 674Srgrimes } 684Srgrimes if (db_next_free_breakpoint == &db_break_table[NBREAKPOINTS]) { 694Srgrimes db_printf("All breakpoints used.\n"); 704Srgrimes return (0); 714Srgrimes } 724Srgrimes bkpt = db_next_free_breakpoint; 734Srgrimes db_next_free_breakpoint++; 744Srgrimes 754Srgrimes return (bkpt); 764Srgrimes} 774Srgrimes 7812515Sphkstatic void 794Srgrimesdb_breakpoint_free(bkpt) 804Srgrimes register db_breakpoint_t bkpt; 814Srgrimes{ 824Srgrimes bkpt->link = db_free_breakpoints; 834Srgrimes db_free_breakpoints = bkpt; 844Srgrimes} 854Srgrimes 8612515Sphkstatic void 874Srgrimesdb_set_breakpoint(map, addr, count) 884Srgrimes vm_map_t map; 894Srgrimes db_addr_t addr; 904Srgrimes int count; 914Srgrimes{ 924Srgrimes register db_breakpoint_t bkpt; 934Srgrimes 944Srgrimes if (db_find_breakpoint(map, addr)) { 954Srgrimes db_printf("Already set.\n"); 964Srgrimes return; 974Srgrimes } 984Srgrimes 994Srgrimes bkpt = db_breakpoint_alloc(); 1004Srgrimes if (bkpt == 0) { 1014Srgrimes db_printf("Too many breakpoints.\n"); 1024Srgrimes return; 1034Srgrimes } 1044Srgrimes 1054Srgrimes bkpt->map = map; 1064Srgrimes bkpt->address = addr; 1074Srgrimes bkpt->flags = 0; 1084Srgrimes bkpt->init_count = count; 1094Srgrimes bkpt->count = count; 1104Srgrimes 1114Srgrimes bkpt->link = db_breakpoint_list; 1124Srgrimes db_breakpoint_list = bkpt; 1134Srgrimes} 1144Srgrimes 11512515Sphkstatic void 1164Srgrimesdb_delete_breakpoint(map, addr) 1174Srgrimes vm_map_t map; 1184Srgrimes db_addr_t addr; 1194Srgrimes{ 1204Srgrimes register db_breakpoint_t bkpt; 1214Srgrimes register db_breakpoint_t *prev; 1224Srgrimes 1234Srgrimes for (prev = &db_breakpoint_list; 1244Srgrimes (bkpt = *prev) != 0; 1254Srgrimes prev = &bkpt->link) { 1264Srgrimes if (db_map_equal(bkpt->map, map) && 1274Srgrimes (bkpt->address == addr)) { 1284Srgrimes *prev = bkpt->link; 1294Srgrimes break; 1304Srgrimes } 1314Srgrimes } 1324Srgrimes if (bkpt == 0) { 1334Srgrimes db_printf("Not set.\n"); 1344Srgrimes return; 1354Srgrimes } 1364Srgrimes 1374Srgrimes db_breakpoint_free(bkpt); 1384Srgrimes} 1394Srgrimes 14012515Sphkstatic db_breakpoint_t 1414Srgrimesdb_find_breakpoint(map, addr) 1424Srgrimes vm_map_t map; 1434Srgrimes db_addr_t addr; 1444Srgrimes{ 1454Srgrimes register db_breakpoint_t bkpt; 1464Srgrimes 1474Srgrimes for (bkpt = db_breakpoint_list; 1484Srgrimes bkpt != 0; 1494Srgrimes bkpt = bkpt->link) 1504Srgrimes { 1514Srgrimes if (db_map_equal(bkpt->map, map) && 1524Srgrimes (bkpt->address == addr)) 1534Srgrimes return (bkpt); 1544Srgrimes } 1554Srgrimes return (0); 1564Srgrimes} 1574Srgrimes 1584Srgrimesdb_breakpoint_t 1594Srgrimesdb_find_breakpoint_here(addr) 1604Srgrimes db_addr_t addr; 1614Srgrimes{ 1624Srgrimes return db_find_breakpoint(db_map_addr(addr), addr); 1634Srgrimes} 1644Srgrimes 16512515Sphkstatic boolean_t db_breakpoints_inserted = TRUE; 1664Srgrimes 16783506Sdfr#ifndef BKPT_WRITE 16883506Sdfr#define BKPT_WRITE(addr, storage) \ 16983506Sdfrdo { \ 17083506Sdfr *storage = db_get_value(addr, BKPT_SIZE, FALSE); \ 17183506Sdfr db_put_value(addr, BKPT_SIZE, BKPT_SET(*storage)); \ 17283506Sdfr} while (0) 17383506Sdfr#endif 17483506Sdfr 17583506Sdfr#ifndef BKPT_CLEAR 17683506Sdfr#define BKPT_CLEAR(addr, storage) \ 17783506Sdfr db_put_value(addr, BKPT_SIZE, *storage) 17883506Sdfr#endif 17983506Sdfr 1804Srgrimesvoid 1814Srgrimesdb_set_breakpoints() 1824Srgrimes{ 1834Srgrimes register db_breakpoint_t bkpt; 1844Srgrimes 1854Srgrimes if (!db_breakpoints_inserted) { 1864Srgrimes 18783506Sdfr for (bkpt = db_breakpoint_list; 18883506Sdfr bkpt != 0; 18983506Sdfr bkpt = bkpt->link) 19083506Sdfr if (db_map_current(bkpt->map)) { 19183506Sdfr BKPT_WRITE(bkpt->address, &bkpt->bkpt_inst); 19283506Sdfr } 19383506Sdfr db_breakpoints_inserted = TRUE; 1944Srgrimes } 1954Srgrimes} 1964Srgrimes 1974Srgrimesvoid 1984Srgrimesdb_clear_breakpoints() 1994Srgrimes{ 2004Srgrimes register db_breakpoint_t bkpt; 2014Srgrimes 2024Srgrimes if (db_breakpoints_inserted) { 2034Srgrimes 20483506Sdfr for (bkpt = db_breakpoint_list; 20583506Sdfr bkpt != 0; 20683506Sdfr bkpt = bkpt->link) 20783506Sdfr if (db_map_current(bkpt->map)) { 20883506Sdfr BKPT_CLEAR(bkpt->address, &bkpt->bkpt_inst); 20983506Sdfr } 21083506Sdfr db_breakpoints_inserted = FALSE; 2114Srgrimes } 2124Srgrimes} 2134Srgrimes 21436735Sdfr#ifdef SOFTWARE_SSTEP 2154Srgrimes/* 2164Srgrimes * Set a temporary breakpoint. 2174Srgrimes * The instruction is changed immediately, 2184Srgrimes * so the breakpoint does not have to be on the breakpoint list. 2194Srgrimes */ 22036735Sdfrdb_breakpoint_t 2214Srgrimesdb_set_temp_breakpoint(addr) 2224Srgrimes db_addr_t addr; 2234Srgrimes{ 2244Srgrimes register db_breakpoint_t bkpt; 2254Srgrimes 2264Srgrimes bkpt = db_breakpoint_alloc(); 2274Srgrimes if (bkpt == 0) { 2284Srgrimes db_printf("Too many breakpoints.\n"); 2294Srgrimes return 0; 2304Srgrimes } 2314Srgrimes 2324Srgrimes bkpt->map = NULL; 2334Srgrimes bkpt->address = addr; 2344Srgrimes bkpt->flags = BKPT_TEMP; 2354Srgrimes bkpt->init_count = 1; 2364Srgrimes bkpt->count = 1; 2374Srgrimes 23883506Sdfr BKPT_WRITE(bkpt->address, &bkpt->bkpt_inst); 2394Srgrimes return bkpt; 2404Srgrimes} 2414Srgrimes 24236735Sdfrvoid 2434Srgrimesdb_delete_temp_breakpoint(bkpt) 2444Srgrimes db_breakpoint_t bkpt; 2454Srgrimes{ 24683506Sdfr BKPT_CLEAR(bkpt->address, &bkpt->bkpt_inst); 2474Srgrimes db_breakpoint_free(bkpt); 2484Srgrimes} 24936745Sbde#endif /* SOFTWARE_SSTEP */ 25036735Sdfr 2514Srgrimes/* 2524Srgrimes * List breakpoints. 2534Srgrimes */ 25412515Sphkstatic void 2554Srgrimesdb_list_breakpoints() 2564Srgrimes{ 2574Srgrimes register db_breakpoint_t bkpt; 2584Srgrimes 2594Srgrimes if (db_breakpoint_list == 0) { 2604Srgrimes db_printf("No breakpoints set\n"); 2614Srgrimes return; 2624Srgrimes } 2634Srgrimes 2644Srgrimes db_printf(" Map Count Address\n"); 2654Srgrimes for (bkpt = db_breakpoint_list; 2664Srgrimes bkpt != 0; 26737497Sbde bkpt = bkpt->link) { 26837497Sbde db_printf("%s%8p %5d ", 2694Srgrimes db_map_current(bkpt->map) ? "*" : " ", 27037497Sbde (void *)bkpt->map, bkpt->init_count); 2714Srgrimes db_printsym(bkpt->address, DB_STGY_PROC); 2724Srgrimes db_printf("\n"); 2734Srgrimes } 2744Srgrimes} 2754Srgrimes 2764Srgrimes/* Delete breakpoint */ 2774Srgrimes/*ARGSUSED*/ 2784Srgrimesvoid 2794Srgrimesdb_delete_cmd(addr, have_addr, count, modif) 2804Srgrimes db_expr_t addr; 28112473Sbde boolean_t have_addr; 2824Srgrimes db_expr_t count; 2834Srgrimes char * modif; 2844Srgrimes{ 2854Srgrimes db_delete_breakpoint(db_map_addr(addr), (db_addr_t)addr); 2864Srgrimes} 2874Srgrimes 2884Srgrimes/* Set breakpoint with skip count */ 2894Srgrimes/*ARGSUSED*/ 2904Srgrimesvoid 2914Srgrimesdb_breakpoint_cmd(addr, have_addr, count, modif) 2924Srgrimes db_expr_t addr; 29312473Sbde boolean_t have_addr; 2944Srgrimes db_expr_t count; 2954Srgrimes char * modif; 2964Srgrimes{ 2974Srgrimes if (count == -1) 2984Srgrimes count = 1; 2994Srgrimes 3004Srgrimes db_set_breakpoint(db_map_addr(addr), (db_addr_t)addr, count); 3014Srgrimes} 3024Srgrimes 3034Srgrimes/* list breakpoints */ 3044Srgrimesvoid 30512473Sbdedb_listbreak_cmd(dummy1, dummy2, dummy3, dummy4) 30612473Sbde db_expr_t dummy1; 30712473Sbde boolean_t dummy2; 30812473Sbde db_expr_t dummy3; 30912473Sbde char * dummy4; 3104Srgrimes{ 3114Srgrimes db_list_breakpoints(); 3124Srgrimes} 3134Srgrimes 3144Srgrimes/* 3154Srgrimes * We want ddb to be usable before most of the kernel has been 3164Srgrimes * initialized. In particular, current_thread() or kernel_map 3174Srgrimes * (or both) may be null. 3184Srgrimes */ 3194Srgrimes 3204Srgrimesboolean_t 3214Srgrimesdb_map_equal(map1, map2) 3224Srgrimes vm_map_t map1, map2; 3234Srgrimes{ 3244Srgrimes return ((map1 == map2) || 3254Srgrimes ((map1 == NULL) && (map2 == kernel_map)) || 3264Srgrimes ((map1 == kernel_map) && (map2 == NULL))); 3274Srgrimes} 3284Srgrimes 3294Srgrimesboolean_t 3304Srgrimesdb_map_current(map) 3314Srgrimes vm_map_t map; 3324Srgrimes{ 3334Srgrimes#if 0 3344Srgrimes thread_t thread; 3354Srgrimes 3364Srgrimes return ((map == NULL) || 3374Srgrimes (map == kernel_map) || 3384Srgrimes (((thread = current_thread()) != NULL) && 3394Srgrimes (map == thread->task->map))); 3404Srgrimes#else 3414Srgrimes return (1); 3424Srgrimes#endif 3434Srgrimes} 3444Srgrimes 3454Srgrimesvm_map_t 3464Srgrimesdb_map_addr(addr) 3474Srgrimes vm_offset_t addr; 3484Srgrimes{ 3494Srgrimes#if 0 3504Srgrimes thread_t thread; 3514Srgrimes 3524Srgrimes /* 3534Srgrimes * We want to return kernel_map for all 3544Srgrimes * non-user addresses, even when debugging 3554Srgrimes * kernel tasks with their own maps. 3564Srgrimes */ 3574Srgrimes 3584Srgrimes if ((VM_MIN_ADDRESS <= addr) && 3594Srgrimes (addr < VM_MAX_ADDRESS) && 3604Srgrimes ((thread = current_thread()) != NULL)) 3614Srgrimes return thread->task->map; 3624Srgrimes else 3634Srgrimes#endif 3644Srgrimes return kernel_map; 3654Srgrimes} 366