db_break.c revision 8876
1168404Spjd/* 2168404Spjd * Mach Operating System 3168404Spjd * Copyright (c) 1991,1990 Carnegie Mellon University 4168404Spjd * All Rights Reserved. 5168404Spjd * 6168404Spjd * Permission to use, copy, modify and distribute this software and its 7168404Spjd * documentation is hereby granted, provided that both the copyright 8168404Spjd * notice and this permission notice appear in all copies of the 9168404Spjd * software, derivative works or modified versions, and any portions 10168404Spjd * thereof, and that both notices appear in supporting documentation. 11168404Spjd * 12168404Spjd * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS 13168404Spjd * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR 14168404Spjd * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 15168404Spjd * 16168404Spjd * Carnegie Mellon requests users of this software to return to 17168404Spjd * 18168404Spjd * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 19168404Spjd * School of Computer Science 20168404Spjd * Carnegie Mellon University 21168404Spjd * Pittsburgh PA 15213-3890 22208373Smm * 23168404Spjd * any improvements or extensions that they make and grant Carnegie the 24168404Spjd * rights to redistribute these changes. 25168404Spjd * 26168404Spjd * $Id: db_break.c,v 1.5 1994/08/18 22:34:19 wollman Exp $ 27168404Spjd */ 28168404Spjd 29168404Spjd/* 30168404Spjd * Author: David B. Golub, Carnegie Mellon University 31168404Spjd * Date: 7/90 32168404Spjd */ 33168404Spjd/* 34168404Spjd * Breakpoints. 35168404Spjd */ 36168404Spjd#include <sys/param.h> 37168404Spjd#include <sys/systm.h> 38168404Spjd#include <sys/proc.h> 39168404Spjd#include <ddb/ddb.h> 40168404Spjd 41168404Spjd#include <ddb/db_lex.h> 42168404Spjd#include <ddb/db_break.h> 43168404Spjd#include <ddb/db_access.h> 44168404Spjd#include <ddb/db_sym.h> 45168404Spjd#include <ddb/db_break.h> 46168404Spjd 47168404Spjd#define NBREAKPOINTS 100 48185029Spjdstruct db_breakpoint db_break_table[NBREAKPOINTS]; 49185029Spjddb_breakpoint_t db_next_free_breakpoint = &db_break_table[0]; 50168404Spjddb_breakpoint_t db_free_breakpoints = 0; 51168404Spjddb_breakpoint_t db_breakpoint_list = 0; 52168404Spjd 53168404Spjddb_breakpoint_t 54185029Spjddb_breakpoint_alloc() 55168404Spjd{ 56168404Spjd register db_breakpoint_t bkpt; 57168404Spjd 58168404Spjd if ((bkpt = db_free_breakpoints) != 0) { 59168404Spjd db_free_breakpoints = bkpt->link; 60168404Spjd return (bkpt); 61168404Spjd } 62168404Spjd if (db_next_free_breakpoint == &db_break_table[NBREAKPOINTS]) { 63168404Spjd db_printf("All breakpoints used.\n"); 64168404Spjd return (0); 65168404Spjd } 66168404Spjd bkpt = db_next_free_breakpoint; 67168404Spjd db_next_free_breakpoint++; 68168404Spjd 69168404Spjd return (bkpt); 70168404Spjd} 71168404Spjd 72168404Spjdvoid 73168404Spjddb_breakpoint_free(bkpt) 74168404Spjd register db_breakpoint_t bkpt; 75168404Spjd{ 76185029Spjd bkpt->link = db_free_breakpoints; 77168404Spjd db_free_breakpoints = bkpt; 78168404Spjd} 79168404Spjd 80168404Spjdvoid 81168404Spjddb_set_breakpoint(map, addr, count) 82168404Spjd vm_map_t map; 83168404Spjd db_addr_t addr; 84168404Spjd int count; 85168404Spjd{ 86168404Spjd register db_breakpoint_t bkpt; 87168404Spjd 88168404Spjd if (db_find_breakpoint(map, addr)) { 89168404Spjd db_printf("Already set.\n"); 90168404Spjd return; 91168404Spjd } 92168404Spjd 93168404Spjd bkpt = db_breakpoint_alloc(); 94168404Spjd if (bkpt == 0) { 95168404Spjd db_printf("Too many breakpoints.\n"); 96168404Spjd return; 97168404Spjd } 98168404Spjd 99168404Spjd bkpt->map = map; 100168404Spjd bkpt->address = addr; 101168404Spjd bkpt->flags = 0; 102168404Spjd bkpt->init_count = count; 103168404Spjd bkpt->count = count; 104168404Spjd 105168404Spjd bkpt->link = db_breakpoint_list; 106168404Spjd db_breakpoint_list = bkpt; 107168404Spjd} 108168404Spjd 109168404Spjdvoid 110185029Spjddb_delete_breakpoint(map, addr) 111185029Spjd vm_map_t map; 112185029Spjd db_addr_t addr; 113185029Spjd{ 114185029Spjd register db_breakpoint_t bkpt; 115185029Spjd register db_breakpoint_t *prev; 116185029Spjd 117185029Spjd for (prev = &db_breakpoint_list; 118168404Spjd (bkpt = *prev) != 0; 119168404Spjd prev = &bkpt->link) { 120168404Spjd if (db_map_equal(bkpt->map, map) && 121168404Spjd (bkpt->address == addr)) { 122168404Spjd *prev = bkpt->link; 123168404Spjd break; 124168404Spjd } 125168404Spjd } 126185029Spjd if (bkpt == 0) { 127168404Spjd db_printf("Not set.\n"); 128168404Spjd return; 129168404Spjd } 130168404Spjd 131168404Spjd db_breakpoint_free(bkpt); 132168404Spjd} 133168404Spjd 134191902Skmacydb_breakpoint_t 135191902Skmacydb_find_breakpoint(map, addr) 136168404Spjd vm_map_t map; 137168404Spjd db_addr_t addr; 138168404Spjd{ 139168404Spjd register db_breakpoint_t bkpt; 140185029Spjd 141185029Spjd for (bkpt = db_breakpoint_list; 142185029Spjd bkpt != 0; 143185029Spjd bkpt = bkpt->link) 144168404Spjd { 145168404Spjd if (db_map_equal(bkpt->map, map) && 146168404Spjd (bkpt->address == addr)) 147168404Spjd return (bkpt); 148168404Spjd } 149168404Spjd return (0); 150168404Spjd} 151168404Spjd 152168404Spjddb_breakpoint_t 153168404Spjddb_find_breakpoint_here(addr) 154168404Spjd db_addr_t addr; 155208373Smm{ 156208373Smm return db_find_breakpoint(db_map_addr(addr), addr); 157208373Smm} 158208373Smm 159208373Smmboolean_t db_breakpoints_inserted = TRUE; 160208373Smm 161168404Spjdvoid 162168404Spjddb_set_breakpoints() 163168404Spjd{ 164168404Spjd register db_breakpoint_t bkpt; 165168404Spjd 166168404Spjd if (!db_breakpoints_inserted) { 167208373Smm 168194043Skmacy for (bkpt = db_breakpoint_list; 169168404Spjd bkpt != 0; 170168404Spjd bkpt = bkpt->link) 171185029Spjd if (db_map_current(bkpt->map)) { 172185029Spjd bkpt->bkpt_inst = db_get_value(bkpt->address, 173185029Spjd BKPT_SIZE, 174185029Spjd FALSE); 175185029Spjd db_put_value(bkpt->address, 176168404Spjd BKPT_SIZE, 177168404Spjd BKPT_SET(bkpt->bkpt_inst)); 178185029Spjd } 179185029Spjd db_breakpoints_inserted = TRUE; 180185029Spjd } 181185029Spjd} 182208373Smm 183208373Smmvoid 184208373Smmdb_clear_breakpoints() 185185029Spjd{ 186185029Spjd register db_breakpoint_t bkpt; 187185029Spjd 188185029Spjd if (db_breakpoints_inserted) { 189185029Spjd 190168473Spjd for (bkpt = db_breakpoint_list; 191185029Spjd bkpt != 0; 192168473Spjd bkpt = bkpt->link) 193185029Spjd if (db_map_current(bkpt->map)) { 194168473Spjd db_put_value(bkpt->address, BKPT_SIZE, bkpt->bkpt_inst); 195185029Spjd } 196185029Spjd db_breakpoints_inserted = FALSE; 197168404Spjd } 198168404Spjd} 199185029Spjd 200168404Spjd/* 201168404Spjd * Set a temporary breakpoint. 202168404Spjd * The instruction is changed immediately, 203168404Spjd * so the breakpoint does not have to be on the breakpoint list. 204168404Spjd */ 205185029Spjddb_breakpoint_t 206185029Spjddb_set_temp_breakpoint(addr) 207185029Spjd db_addr_t addr; 208185029Spjd{ 209185029Spjd register db_breakpoint_t bkpt; 210185029Spjd 211185029Spjd bkpt = db_breakpoint_alloc(); 212185029Spjd if (bkpt == 0) { 213168404Spjd db_printf("Too many breakpoints.\n"); 214168404Spjd return 0; 215168404Spjd } 216168404Spjd 217168404Spjd bkpt->map = NULL; 218168404Spjd bkpt->address = addr; 219168404Spjd bkpt->flags = BKPT_TEMP; 220185029Spjd bkpt->init_count = 1; 221185029Spjd bkpt->count = 1; 222185029Spjd 223185029Spjd bkpt->bkpt_inst = db_get_value(bkpt->address, BKPT_SIZE, FALSE); 224185029Spjd db_put_value(bkpt->address, BKPT_SIZE, BKPT_SET(bkpt->bkpt_inst)); 225185029Spjd return bkpt; 226185029Spjd} 227185029Spjd 228168404Spjdvoid 229168404Spjddb_delete_temp_breakpoint(bkpt) 230205264Skmacy db_breakpoint_t bkpt; 231205231Skmacy{ 232205231Skmacy db_put_value(bkpt->address, BKPT_SIZE, bkpt->bkpt_inst); 233205231Skmacy db_breakpoint_free(bkpt); 234205231Skmacy} 235205231Skmacy 236205231Skmacy/* 237205231Skmacy * List breakpoints. 238205231Skmacy */ 239205231Skmacyvoid 240205231Skmacydb_list_breakpoints() 241205231Skmacy{ 242205231Skmacy register db_breakpoint_t bkpt; 243205231Skmacy 244206796Spjd if (db_breakpoint_list == 0) { 245205231Skmacy db_printf("No breakpoints set\n"); 246168404Spjd return; 247185029Spjd } 248185029Spjd 249205231Skmacy db_printf(" Map Count Address\n"); 250205264Skmacy for (bkpt = db_breakpoint_list; 251168404Spjd bkpt != 0; 252168404Spjd bkpt = bkpt->link) 253206796Spjd { 254205231Skmacy db_printf("%s%8x %5d ", 255185029Spjd db_map_current(bkpt->map) ? "*" : " ", 256168404Spjd bkpt->map, bkpt->init_count); 257168404Spjd db_printsym(bkpt->address, DB_STGY_PROC); 258168404Spjd db_printf("\n"); 259168404Spjd } 260168404Spjd} 261185029Spjd 262168404Spjd/* Delete breakpoint */ 263168404Spjd/*ARGSUSED*/ 264168404Spjdvoid 265168404Spjddb_delete_cmd(addr, have_addr, count, modif) 266168404Spjd db_expr_t addr; 267168404Spjd int have_addr; 268168404Spjd db_expr_t count; 269168404Spjd char * modif; 270168404Spjd{ 271168404Spjd db_delete_breakpoint(db_map_addr(addr), (db_addr_t)addr); 272168404Spjd} 273168404Spjd 274168404Spjd/* Set breakpoint with skip count */ 275168404Spjd/*ARGSUSED*/ 276168404Spjdvoid 277168404Spjddb_breakpoint_cmd(addr, have_addr, count, modif) 278205231Skmacy db_expr_t addr; 279168404Spjd int have_addr; 280205231Skmacy db_expr_t count; 281168404Spjd char * modif; 282168404Spjd{ 283168404Spjd if (count == -1) 284208373Smm count = 1; 285208373Smm 286208373Smm db_set_breakpoint(db_map_addr(addr), (db_addr_t)addr, count); 287168404Spjd} 288168404Spjd 289168404Spjd/* list breakpoints */ 290168404Spjdvoid 291168404Spjddb_listbreak_cmd(db_expr_t dummy1, int dummy2, db_expr_t dummy3, char *dummy4) 292168404Spjd{ 293168404Spjd db_list_breakpoints(); 294168404Spjd} 295168404Spjd 296168404Spjd#include <vm/vm_kern.h> 297185029Spjd 298208373Smm/* 299208373Smm * We want ddb to be usable before most of the kernel has been 300185029Spjd * initialized. In particular, current_thread() or kernel_map 301185029Spjd * (or both) may be null. 302185029Spjd */ 303185029Spjd 304208373Smmboolean_t 305208373Smmdb_map_equal(map1, map2) 306185029Spjd vm_map_t map1, map2; 307185029Spjd{ 308185029Spjd return ((map1 == map2) || 309185029Spjd ((map1 == NULL) && (map2 == kernel_map)) || 310185029Spjd ((map1 == kernel_map) && (map2 == NULL))); 311185029Spjd} 312185029Spjd 313185029Spjdboolean_t 314185029Spjddb_map_current(map) 315185029Spjd vm_map_t map; 316185029Spjd{ 317185029Spjd#if 0 318185029Spjd thread_t thread; 319205231Skmacy 320205231Skmacy return ((map == NULL) || 321205231Skmacy (map == kernel_map) || 322206796Spjd (((thread = current_thread()) != NULL) && 323205231Skmacy (map == thread->task->map))); 324205231Skmacy#else 325205231Skmacy return (1); 326205231Skmacy#endif 327205231Skmacy} 328205231Skmacy 329205231Skmacyvm_map_t 330205231Skmacydb_map_addr(addr) 331168404Spjd vm_offset_t addr; 332168404Spjd{ 333168404Spjd#if 0 334168404Spjd thread_t thread; 335168404Spjd 336168404Spjd /* 337168404Spjd * We want to return kernel_map for all 338168404Spjd * non-user addresses, even when debugging 339168404Spjd * kernel tasks with their own maps. 340168404Spjd */ 341168404Spjd 342168404Spjd if ((VM_MIN_ADDRESS <= addr) && 343168404Spjd (addr < VM_MAX_ADDRESS) && 344168404Spjd ((thread = current_thread()) != NULL)) 345168404Spjd return thread->task->map; 346168404Spjd else 347168404Spjd#endif 348205231Skmacy return kernel_map; 349168404Spjd} 350205231Skmacy