1dd3cb568SWarner Losh /*- 25b81b6b3SRodney W. Grimes * Mach Operating System 35b81b6b3SRodney W. Grimes * Copyright (c) 1991,1990 Carnegie Mellon University 45b81b6b3SRodney W. Grimes * All Rights Reserved. 55b81b6b3SRodney W. Grimes * 65b81b6b3SRodney W. Grimes * Permission to use, copy, modify and distribute this software and its 75b81b6b3SRodney W. Grimes * documentation is hereby granted, provided that both the copyright 85b81b6b3SRodney W. Grimes * notice and this permission notice appear in all copies of the 95b81b6b3SRodney W. Grimes * software, derivative works or modified versions, and any portions 105b81b6b3SRodney W. Grimes * thereof, and that both notices appear in supporting documentation. 115b81b6b3SRodney W. Grimes * 125b81b6b3SRodney W. Grimes * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS 135b81b6b3SRodney W. Grimes * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR 145b81b6b3SRodney W. Grimes * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 155b81b6b3SRodney W. Grimes * 165b81b6b3SRodney W. Grimes * Carnegie Mellon requests users of this software to return to 175b81b6b3SRodney W. Grimes * 185b81b6b3SRodney W. Grimes * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 195b81b6b3SRodney W. Grimes * School of Computer Science 205b81b6b3SRodney W. Grimes * Carnegie Mellon University 215b81b6b3SRodney W. Grimes * Pittsburgh PA 15213-3890 225b81b6b3SRodney W. Grimes * 235b81b6b3SRodney W. Grimes * any improvements or extensions that they make and grant Carnegie the 245b81b6b3SRodney W. Grimes * rights to redistribute these changes. 250edf66ecSRodney W. Grimes * 265b81b6b3SRodney W. Grimes */ 275b81b6b3SRodney W. Grimes /* 285b81b6b3SRodney W. Grimes * Author: David B. Golub, Carnegie Mellon University 295b81b6b3SRodney W. Grimes * Date: 7/90 305b81b6b3SRodney W. Grimes */ 315b81b6b3SRodney W. Grimes /* 325b81b6b3SRodney W. Grimes * Breakpoints. 335b81b6b3SRodney W. Grimes */ 34753960f7SDavid E. O'Brien 35753960f7SDavid E. O'Brien #include <sys/cdefs.h> 36753960f7SDavid E. O'Brien __FBSDID("$FreeBSD$"); 37753960f7SDavid E. O'Brien 38f540b106SGarrett Wollman #include <sys/param.h> 395b81b6b3SRodney W. Grimes 405ccbc3ccSBruce Evans #include <vm/vm.h> 415ccbc3ccSBruce Evans #include <vm/vm_kern.h> 425ccbc3ccSBruce Evans 435ccbc3ccSBruce Evans #include <ddb/ddb.h> 445b81b6b3SRodney W. Grimes #include <ddb/db_break.h> 455b81b6b3SRodney W. Grimes #include <ddb/db_access.h> 465b81b6b3SRodney W. Grimes #include <ddb/db_sym.h> 475b81b6b3SRodney W. Grimes 485b81b6b3SRodney W. Grimes #define NBREAKPOINTS 100 4925eb640dSPoul-Henning Kamp static struct db_breakpoint db_break_table[NBREAKPOINTS]; 50f73a856dSPoul-Henning Kamp static db_breakpoint_t db_next_free_breakpoint = &db_break_table[0]; 51f73a856dSPoul-Henning Kamp static db_breakpoint_t db_free_breakpoints = 0; 52f73a856dSPoul-Henning Kamp static db_breakpoint_t db_breakpoint_list = 0; 535b81b6b3SRodney W. Grimes 5414e10f99SAlfred Perlstein static db_breakpoint_t db_breakpoint_alloc(void); 5514e10f99SAlfred Perlstein static void db_breakpoint_free(db_breakpoint_t bkpt); 5614e10f99SAlfred Perlstein static void db_delete_breakpoint(vm_map_t map, db_addr_t addr); 5714e10f99SAlfred Perlstein static db_breakpoint_t db_find_breakpoint(vm_map_t map, db_addr_t addr); 5814e10f99SAlfred Perlstein static void db_list_breakpoints(void); 5914e10f99SAlfred Perlstein static void db_set_breakpoint(vm_map_t map, db_addr_t addr, int count); 60f73a856dSPoul-Henning Kamp 61f73a856dSPoul-Henning Kamp static db_breakpoint_t 62a41dd031SPedro F. Giffuni db_breakpoint_alloc(void) 635b81b6b3SRodney W. Grimes { 645b81b6b3SRodney W. Grimes register db_breakpoint_t bkpt; 655b81b6b3SRodney W. Grimes 665b81b6b3SRodney W. Grimes if ((bkpt = db_free_breakpoints) != 0) { 675b81b6b3SRodney W. Grimes db_free_breakpoints = bkpt->link; 685b81b6b3SRodney W. Grimes return (bkpt); 695b81b6b3SRodney W. Grimes } 705b81b6b3SRodney W. Grimes if (db_next_free_breakpoint == &db_break_table[NBREAKPOINTS]) { 715b81b6b3SRodney W. Grimes db_printf("All breakpoints used.\n"); 725b81b6b3SRodney W. Grimes return (0); 735b81b6b3SRodney W. Grimes } 745b81b6b3SRodney W. Grimes bkpt = db_next_free_breakpoint; 755b81b6b3SRodney W. Grimes db_next_free_breakpoint++; 765b81b6b3SRodney W. Grimes 775b81b6b3SRodney W. Grimes return (bkpt); 785b81b6b3SRodney W. Grimes } 795b81b6b3SRodney W. Grimes 80f73a856dSPoul-Henning Kamp static void 81a41dd031SPedro F. Giffuni db_breakpoint_free(db_breakpoint_t bkpt) 825b81b6b3SRodney W. Grimes { 835b81b6b3SRodney W. Grimes bkpt->link = db_free_breakpoints; 845b81b6b3SRodney W. Grimes db_free_breakpoints = bkpt; 855b81b6b3SRodney W. Grimes } 865b81b6b3SRodney W. Grimes 87f73a856dSPoul-Henning Kamp static void 88a41dd031SPedro F. Giffuni db_set_breakpoint(vm_map_t map, db_addr_t addr, int count) 895b81b6b3SRodney W. Grimes { 905b81b6b3SRodney W. Grimes register db_breakpoint_t bkpt; 915b81b6b3SRodney W. Grimes 925b81b6b3SRodney W. Grimes if (db_find_breakpoint(map, addr)) { 935b81b6b3SRodney W. Grimes db_printf("Already set.\n"); 945b81b6b3SRodney W. Grimes return; 955b81b6b3SRodney W. Grimes } 965b81b6b3SRodney W. Grimes 975b81b6b3SRodney W. Grimes bkpt = db_breakpoint_alloc(); 985b81b6b3SRodney W. Grimes if (bkpt == 0) { 995b81b6b3SRodney W. Grimes db_printf("Too many breakpoints.\n"); 1005b81b6b3SRodney W. Grimes return; 1015b81b6b3SRodney W. Grimes } 1025b81b6b3SRodney W. Grimes 1035b81b6b3SRodney W. Grimes bkpt->map = map; 1045b81b6b3SRodney W. Grimes bkpt->address = addr; 1055b81b6b3SRodney W. Grimes bkpt->flags = 0; 1065b81b6b3SRodney W. Grimes bkpt->init_count = count; 1075b81b6b3SRodney W. Grimes bkpt->count = count; 1085b81b6b3SRodney W. Grimes 1095b81b6b3SRodney W. Grimes bkpt->link = db_breakpoint_list; 1105b81b6b3SRodney W. Grimes db_breakpoint_list = bkpt; 1115b81b6b3SRodney W. Grimes } 1125b81b6b3SRodney W. Grimes 113f73a856dSPoul-Henning Kamp static void 114a41dd031SPedro F. Giffuni db_delete_breakpoint(vm_map_t map, db_addr_t addr) 1155b81b6b3SRodney W. Grimes { 1165b81b6b3SRodney W. Grimes register db_breakpoint_t bkpt; 1175b81b6b3SRodney W. Grimes register db_breakpoint_t *prev; 1185b81b6b3SRodney W. Grimes 1195b81b6b3SRodney W. Grimes for (prev = &db_breakpoint_list; 1205b81b6b3SRodney W. Grimes (bkpt = *prev) != 0; 1215b81b6b3SRodney W. Grimes prev = &bkpt->link) { 1225b81b6b3SRodney W. Grimes if (db_map_equal(bkpt->map, map) && 1235b81b6b3SRodney W. Grimes (bkpt->address == addr)) { 1245b81b6b3SRodney W. Grimes *prev = bkpt->link; 1255b81b6b3SRodney W. Grimes break; 1265b81b6b3SRodney W. Grimes } 1275b81b6b3SRodney W. Grimes } 1285b81b6b3SRodney W. Grimes if (bkpt == 0) { 1295b81b6b3SRodney W. Grimes db_printf("Not set.\n"); 1305b81b6b3SRodney W. Grimes return; 1315b81b6b3SRodney W. Grimes } 1325b81b6b3SRodney W. Grimes 1335b81b6b3SRodney W. Grimes db_breakpoint_free(bkpt); 1345b81b6b3SRodney W. Grimes } 1355b81b6b3SRodney W. Grimes 136f73a856dSPoul-Henning Kamp static db_breakpoint_t 137a41dd031SPedro F. Giffuni db_find_breakpoint(vm_map_t map, db_addr_t addr) 1385b81b6b3SRodney W. Grimes { 1395b81b6b3SRodney W. Grimes register db_breakpoint_t bkpt; 1405b81b6b3SRodney W. Grimes 1415b81b6b3SRodney W. Grimes for (bkpt = db_breakpoint_list; 1425b81b6b3SRodney W. Grimes bkpt != 0; 1435b81b6b3SRodney W. Grimes bkpt = bkpt->link) 1445b81b6b3SRodney W. Grimes { 1455b81b6b3SRodney W. Grimes if (db_map_equal(bkpt->map, map) && 1465b81b6b3SRodney W. Grimes (bkpt->address == addr)) 1475b81b6b3SRodney W. Grimes return (bkpt); 1485b81b6b3SRodney W. Grimes } 1495b81b6b3SRodney W. Grimes return (0); 1505b81b6b3SRodney W. Grimes } 1515b81b6b3SRodney W. Grimes 1525b81b6b3SRodney W. Grimes db_breakpoint_t 153a41dd031SPedro F. Giffuni db_find_breakpoint_here(db_addr_t addr) 1545b81b6b3SRodney W. Grimes { 1555b81b6b3SRodney W. Grimes return db_find_breakpoint(db_map_addr(addr), addr); 1565b81b6b3SRodney W. Grimes } 1575b81b6b3SRodney W. Grimes 158*cd508278SPedro F. Giffuni static bool db_breakpoints_inserted = true; 1595b81b6b3SRodney W. Grimes 1603a0b4f25SDoug Rabson #ifndef BKPT_WRITE 1613a0b4f25SDoug Rabson #define BKPT_WRITE(addr, storage) \ 1623a0b4f25SDoug Rabson do { \ 1632b490bc7SPedro F. Giffuni *storage = db_get_value(addr, BKPT_SIZE, false); \ 1643a0b4f25SDoug Rabson db_put_value(addr, BKPT_SIZE, BKPT_SET(*storage)); \ 1653a0b4f25SDoug Rabson } while (0) 1663a0b4f25SDoug Rabson #endif 1673a0b4f25SDoug Rabson 1683a0b4f25SDoug Rabson #ifndef BKPT_CLEAR 1693a0b4f25SDoug Rabson #define BKPT_CLEAR(addr, storage) \ 1703a0b4f25SDoug Rabson db_put_value(addr, BKPT_SIZE, *storage) 1713a0b4f25SDoug Rabson #endif 1723a0b4f25SDoug Rabson 1735b81b6b3SRodney W. Grimes void 174a41dd031SPedro F. Giffuni db_set_breakpoints(void) 1755b81b6b3SRodney W. Grimes { 1765b81b6b3SRodney W. Grimes register db_breakpoint_t bkpt; 1775b81b6b3SRodney W. Grimes 1785b81b6b3SRodney W. Grimes if (!db_breakpoints_inserted) { 1795b81b6b3SRodney W. Grimes 1805b81b6b3SRodney W. Grimes for (bkpt = db_breakpoint_list; 1815b81b6b3SRodney W. Grimes bkpt != 0; 1825b81b6b3SRodney W. Grimes bkpt = bkpt->link) 1835b81b6b3SRodney W. Grimes if (db_map_current(bkpt->map)) { 1843a0b4f25SDoug Rabson BKPT_WRITE(bkpt->address, &bkpt->bkpt_inst); 1855b81b6b3SRodney W. Grimes } 1862b490bc7SPedro F. Giffuni db_breakpoints_inserted = true; 1875b81b6b3SRodney W. Grimes } 1885b81b6b3SRodney W. Grimes } 1895b81b6b3SRodney W. Grimes 1905b81b6b3SRodney W. Grimes void 191a41dd031SPedro F. Giffuni db_clear_breakpoints(void) 1925b81b6b3SRodney W. Grimes { 1935b81b6b3SRodney W. Grimes register db_breakpoint_t bkpt; 1945b81b6b3SRodney W. Grimes 1955b81b6b3SRodney W. Grimes if (db_breakpoints_inserted) { 1965b81b6b3SRodney W. Grimes 1975b81b6b3SRodney W. Grimes for (bkpt = db_breakpoint_list; 1985b81b6b3SRodney W. Grimes bkpt != 0; 1995b81b6b3SRodney W. Grimes bkpt = bkpt->link) 2005b81b6b3SRodney W. Grimes if (db_map_current(bkpt->map)) { 2013a0b4f25SDoug Rabson BKPT_CLEAR(bkpt->address, &bkpt->bkpt_inst); 2025b81b6b3SRodney W. Grimes } 2032b490bc7SPedro F. Giffuni db_breakpoints_inserted = false; 2045b81b6b3SRodney W. Grimes } 2055b81b6b3SRodney W. Grimes } 2065b81b6b3SRodney W. Grimes 207ecbb00a2SDoug Rabson #ifdef SOFTWARE_SSTEP 2085b81b6b3SRodney W. Grimes /* 2095b81b6b3SRodney W. Grimes * Set a temporary breakpoint. 2105b81b6b3SRodney W. Grimes * The instruction is changed immediately, 2115b81b6b3SRodney W. Grimes * so the breakpoint does not have to be on the breakpoint list. 2125b81b6b3SRodney W. Grimes */ 213ecbb00a2SDoug Rabson db_breakpoint_t 214a41dd031SPedro F. Giffuni db_set_temp_breakpoint(db_addr_t addr) 2155b81b6b3SRodney W. Grimes { 2165b81b6b3SRodney W. Grimes register db_breakpoint_t bkpt; 2175b81b6b3SRodney W. Grimes 2185b81b6b3SRodney W. Grimes bkpt = db_breakpoint_alloc(); 2195b81b6b3SRodney W. Grimes if (bkpt == 0) { 2205b81b6b3SRodney W. Grimes db_printf("Too many breakpoints.\n"); 2215b81b6b3SRodney W. Grimes return 0; 2225b81b6b3SRodney W. Grimes } 2235b81b6b3SRodney W. Grimes 2245b81b6b3SRodney W. Grimes bkpt->map = NULL; 2255b81b6b3SRodney W. Grimes bkpt->address = addr; 2265b81b6b3SRodney W. Grimes bkpt->flags = BKPT_TEMP; 2275b81b6b3SRodney W. Grimes bkpt->init_count = 1; 2285b81b6b3SRodney W. Grimes bkpt->count = 1; 2295b81b6b3SRodney W. Grimes 2303a0b4f25SDoug Rabson BKPT_WRITE(bkpt->address, &bkpt->bkpt_inst); 2315b81b6b3SRodney W. Grimes return bkpt; 2325b81b6b3SRodney W. Grimes } 2335b81b6b3SRodney W. Grimes 234ecbb00a2SDoug Rabson void 235a41dd031SPedro F. Giffuni db_delete_temp_breakpoint(db_breakpoint_t bkpt) 2365b81b6b3SRodney W. Grimes { 2373a0b4f25SDoug Rabson BKPT_CLEAR(bkpt->address, &bkpt->bkpt_inst); 2385b81b6b3SRodney W. Grimes db_breakpoint_free(bkpt); 2395b81b6b3SRodney W. Grimes } 2404204c166SBruce Evans #endif /* SOFTWARE_SSTEP */ 2415b81b6b3SRodney W. Grimes 2425b81b6b3SRodney W. Grimes /* 2435b81b6b3SRodney W. Grimes * List breakpoints. 2445b81b6b3SRodney W. Grimes */ 245f73a856dSPoul-Henning Kamp static void 246a41dd031SPedro F. Giffuni db_list_breakpoints(void) 2475b81b6b3SRodney W. Grimes { 2485b81b6b3SRodney W. Grimes register db_breakpoint_t bkpt; 2495b81b6b3SRodney W. Grimes 2505b81b6b3SRodney W. Grimes if (db_breakpoint_list == 0) { 2515b81b6b3SRodney W. Grimes db_printf("No breakpoints set\n"); 2525b81b6b3SRodney W. Grimes return; 2535b81b6b3SRodney W. Grimes } 2545b81b6b3SRodney W. Grimes 2555b81b6b3SRodney W. Grimes db_printf(" Map Count Address\n"); 2565b81b6b3SRodney W. Grimes for (bkpt = db_breakpoint_list; 2575b81b6b3SRodney W. Grimes bkpt != 0; 25890163a9bSBruce Evans bkpt = bkpt->link) { 25990163a9bSBruce Evans db_printf("%s%8p %5d ", 2605b81b6b3SRodney W. Grimes db_map_current(bkpt->map) ? "*" : " ", 26190163a9bSBruce Evans (void *)bkpt->map, bkpt->init_count); 2625b81b6b3SRodney W. Grimes db_printsym(bkpt->address, DB_STGY_PROC); 2635b81b6b3SRodney W. Grimes db_printf("\n"); 2645b81b6b3SRodney W. Grimes } 2655b81b6b3SRodney W. Grimes } 2665b81b6b3SRodney W. Grimes 2675b81b6b3SRodney W. Grimes /* Delete breakpoint */ 2685b81b6b3SRodney W. Grimes /*ARGSUSED*/ 2695b81b6b3SRodney W. Grimes void 270*cd508278SPedro F. Giffuni db_delete_cmd(db_expr_t addr, bool have_addr, db_expr_t count, char *modif) 2715b81b6b3SRodney W. Grimes { 2725b81b6b3SRodney W. Grimes db_delete_breakpoint(db_map_addr(addr), (db_addr_t)addr); 2735b81b6b3SRodney W. Grimes } 2745b81b6b3SRodney W. Grimes 2755b81b6b3SRodney W. Grimes /* Set breakpoint with skip count */ 2765b81b6b3SRodney W. Grimes /*ARGSUSED*/ 2775b81b6b3SRodney W. Grimes void 278*cd508278SPedro F. Giffuni db_breakpoint_cmd(db_expr_t addr, bool have_addr, db_expr_t count, char *modif) 2795b81b6b3SRodney W. Grimes { 2805b81b6b3SRodney W. Grimes if (count == -1) 2815b81b6b3SRodney W. Grimes count = 1; 2825b81b6b3SRodney W. Grimes 2835b81b6b3SRodney W. Grimes db_set_breakpoint(db_map_addr(addr), (db_addr_t)addr, count); 2845b81b6b3SRodney W. Grimes } 2855b81b6b3SRodney W. Grimes 2865b81b6b3SRodney W. Grimes /* list breakpoints */ 2875b81b6b3SRodney W. Grimes void 288*cd508278SPedro F. Giffuni db_listbreak_cmd(db_expr_t dummy1, bool dummy2, db_expr_t dummy3, char *dummy4) 2895b81b6b3SRodney W. Grimes { 2905b81b6b3SRodney W. Grimes db_list_breakpoints(); 2915b81b6b3SRodney W. Grimes } 2925b81b6b3SRodney W. Grimes 2935b81b6b3SRodney W. Grimes /* 2945b81b6b3SRodney W. Grimes * We want ddb to be usable before most of the kernel has been 2955b81b6b3SRodney W. Grimes * initialized. In particular, current_thread() or kernel_map 2965b81b6b3SRodney W. Grimes * (or both) may be null. 2975b81b6b3SRodney W. Grimes */ 2985b81b6b3SRodney W. Grimes 299*cd508278SPedro F. Giffuni bool 300a41dd031SPedro F. Giffuni db_map_equal(vm_map_t map1, vm_map_t map2) 3015b81b6b3SRodney W. Grimes { 3025b81b6b3SRodney W. Grimes return ((map1 == map2) || 3035b81b6b3SRodney W. Grimes ((map1 == NULL) && (map2 == kernel_map)) || 3045b81b6b3SRodney W. Grimes ((map1 == kernel_map) && (map2 == NULL))); 3055b81b6b3SRodney W. Grimes } 3065b81b6b3SRodney W. Grimes 307*cd508278SPedro F. Giffuni bool 308a41dd031SPedro F. Giffuni db_map_current(vm_map_t map) 3095b81b6b3SRodney W. Grimes { 3105b81b6b3SRodney W. Grimes #if 0 3115b81b6b3SRodney W. Grimes thread_t thread; 3125b81b6b3SRodney W. Grimes 3135b81b6b3SRodney W. Grimes return ((map == NULL) || 3145b81b6b3SRodney W. Grimes (map == kernel_map) || 3155b81b6b3SRodney W. Grimes (((thread = current_thread()) != NULL) && 3165b81b6b3SRodney W. Grimes (map == thread->task->map))); 3175b81b6b3SRodney W. Grimes #else 318*cd508278SPedro F. Giffuni return (true); 3195b81b6b3SRodney W. Grimes #endif 3205b81b6b3SRodney W. Grimes } 3215b81b6b3SRodney W. Grimes 3225b81b6b3SRodney W. Grimes vm_map_t 323a41dd031SPedro F. Giffuni db_map_addr(vm_offset_t addr) 3245b81b6b3SRodney W. Grimes { 3255b81b6b3SRodney W. Grimes #if 0 3265b81b6b3SRodney W. Grimes thread_t thread; 3275b81b6b3SRodney W. Grimes 3285b81b6b3SRodney W. Grimes /* 3295b81b6b3SRodney W. Grimes * We want to return kernel_map for all 3305b81b6b3SRodney W. Grimes * non-user addresses, even when debugging 3315b81b6b3SRodney W. Grimes * kernel tasks with their own maps. 3325b81b6b3SRodney W. Grimes */ 3335b81b6b3SRodney W. Grimes 3345b81b6b3SRodney W. Grimes if ((VM_MIN_ADDRESS <= addr) && 3355b81b6b3SRodney W. Grimes (addr < VM_MAX_ADDRESS) && 3365b81b6b3SRodney W. Grimes ((thread = current_thread()) != NULL)) 3375b81b6b3SRodney W. Grimes return thread->task->map; 3385b81b6b3SRodney W. Grimes else 3395b81b6b3SRodney W. Grimes #endif 3405b81b6b3SRodney W. Grimes return kernel_map; 3415b81b6b3SRodney W. Grimes } 342