Index: head/sys/ddb/db_break.c =================================================================== --- head/sys/ddb/db_break.c (revision 365226) +++ head/sys/ddb/db_break.c (revision 365227) @@ -1,343 +1,341 @@ /*- * SPDX-License-Identifier: MIT-CMU * * Mach Operating System * Copyright (c) 1991,1990 Carnegie Mellon University * All Rights Reserved. * * Permission to use, copy, modify and distribute this software and its * documentation is hereby granted, provided that both the copyright * notice and this permission notice appear in all copies of the * software, derivative works or modified versions, and any portions * thereof, and that both notices appear in supporting documentation. * * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. * * Carnegie Mellon requests users of this software to return to * * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU * School of Computer Science * Carnegie Mellon University * Pittsburgh PA 15213-3890 * * any improvements or extensions that they make and grant Carnegie the * rights to redistribute these changes. * */ /* * Author: David B. Golub, Carnegie Mellon University * Date: 7/90 */ /* * Breakpoints. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #define NBREAKPOINTS 100 static struct db_breakpoint db_break_table[NBREAKPOINTS]; static db_breakpoint_t db_next_free_breakpoint = &db_break_table[0]; static db_breakpoint_t db_free_breakpoints = 0; static db_breakpoint_t db_breakpoint_list = 0; static db_breakpoint_t db_breakpoint_alloc(void); static void db_breakpoint_free(db_breakpoint_t bkpt); static void db_delete_breakpoint(vm_map_t map, db_addr_t addr); static db_breakpoint_t db_find_breakpoint(vm_map_t map, db_addr_t addr); static void db_list_breakpoints(void); static void db_set_breakpoint(vm_map_t map, db_addr_t addr, int count); static db_breakpoint_t db_breakpoint_alloc(void) { register db_breakpoint_t bkpt; if ((bkpt = db_free_breakpoints) != 0) { db_free_breakpoints = bkpt->link; return (bkpt); } if (db_next_free_breakpoint == &db_break_table[NBREAKPOINTS]) { db_printf("All breakpoints used.\n"); return (0); } bkpt = db_next_free_breakpoint; db_next_free_breakpoint++; return (bkpt); } static void db_breakpoint_free(db_breakpoint_t bkpt) { bkpt->link = db_free_breakpoints; db_free_breakpoints = bkpt; } static void db_set_breakpoint(vm_map_t map, db_addr_t addr, int count) { register db_breakpoint_t bkpt; if (db_find_breakpoint(map, addr)) { db_printf("Already set.\n"); return; } bkpt = db_breakpoint_alloc(); if (bkpt == 0) { db_printf("Too many breakpoints.\n"); return; } bkpt->map = map; bkpt->address = addr; bkpt->flags = 0; bkpt->init_count = count; bkpt->count = count; bkpt->link = db_breakpoint_list; db_breakpoint_list = bkpt; } static void db_delete_breakpoint(vm_map_t map, db_addr_t addr) { register db_breakpoint_t bkpt; register db_breakpoint_t *prev; for (prev = &db_breakpoint_list; (bkpt = *prev) != 0; prev = &bkpt->link) { if (db_map_equal(bkpt->map, map) && (bkpt->address == addr)) { *prev = bkpt->link; break; } } if (bkpt == 0) { db_printf("Not set.\n"); return; } db_breakpoint_free(bkpt); } static db_breakpoint_t db_find_breakpoint(vm_map_t map, db_addr_t addr) { register db_breakpoint_t bkpt; for (bkpt = db_breakpoint_list; bkpt != 0; bkpt = bkpt->link) { if (db_map_equal(bkpt->map, map) && (bkpt->address == addr)) return (bkpt); } return (0); } db_breakpoint_t db_find_breakpoint_here(db_addr_t addr) { return db_find_breakpoint(db_map_addr(addr), addr); } static bool db_breakpoints_inserted = true; #ifndef BKPT_WRITE #define BKPT_WRITE(addr, storage) \ do { \ *storage = db_get_value(addr, BKPT_SIZE, false); \ db_put_value(addr, BKPT_SIZE, BKPT_SET(*storage)); \ } while (0) #endif #ifndef BKPT_CLEAR #define BKPT_CLEAR(addr, storage) \ db_put_value(addr, BKPT_SIZE, *storage) #endif void db_set_breakpoints(void) { register db_breakpoint_t bkpt; if (!db_breakpoints_inserted) { - for (bkpt = db_breakpoint_list; bkpt != 0; bkpt = bkpt->link) if (db_map_current(bkpt->map)) { BKPT_WRITE(bkpt->address, &bkpt->bkpt_inst); } db_breakpoints_inserted = true; } } void db_clear_breakpoints(void) { register db_breakpoint_t bkpt; if (db_breakpoints_inserted) { - for (bkpt = db_breakpoint_list; bkpt != 0; bkpt = bkpt->link) if (db_map_current(bkpt->map)) { BKPT_CLEAR(bkpt->address, &bkpt->bkpt_inst); } db_breakpoints_inserted = false; } } #ifdef SOFTWARE_SSTEP /* * Set a temporary breakpoint. * The instruction is changed immediately, * so the breakpoint does not have to be on the breakpoint list. */ db_breakpoint_t db_set_temp_breakpoint(db_addr_t addr) { register db_breakpoint_t bkpt; bkpt = db_breakpoint_alloc(); if (bkpt == 0) { db_printf("Too many breakpoints.\n"); return 0; } bkpt->map = NULL; bkpt->address = addr; bkpt->flags = BKPT_TEMP; bkpt->init_count = 1; bkpt->count = 1; BKPT_WRITE(bkpt->address, &bkpt->bkpt_inst); return bkpt; } void db_delete_temp_breakpoint(db_breakpoint_t bkpt) { BKPT_CLEAR(bkpt->address, &bkpt->bkpt_inst); db_breakpoint_free(bkpt); } #endif /* SOFTWARE_SSTEP */ /* * List breakpoints. */ static void db_list_breakpoints(void) { register db_breakpoint_t bkpt; if (db_breakpoint_list == 0) { db_printf("No breakpoints set\n"); return; } db_printf(" Map Count Address\n"); for (bkpt = db_breakpoint_list; bkpt != 0; bkpt = bkpt->link) { db_printf("%s%8p %5d ", db_map_current(bkpt->map) ? "*" : " ", (void *)bkpt->map, bkpt->init_count); db_printsym(bkpt->address, DB_STGY_PROC); db_printf("\n"); } } /* Delete breakpoint */ /*ARGSUSED*/ void db_delete_cmd(db_expr_t addr, bool have_addr, db_expr_t count, char *modif) { db_delete_breakpoint(db_map_addr(addr), (db_addr_t)addr); } /* Set breakpoint with skip count */ /*ARGSUSED*/ void db_breakpoint_cmd(db_expr_t addr, bool have_addr, db_expr_t count, char *modif) { if (count == -1) count = 1; db_set_breakpoint(db_map_addr(addr), (db_addr_t)addr, count); } /* list breakpoints */ void db_listbreak_cmd(db_expr_t dummy1, bool dummy2, db_expr_t dummy3, char *dummy4) { db_list_breakpoints(); } /* * We want ddb to be usable before most of the kernel has been * initialized. In particular, current_thread() or kernel_map * (or both) may be null. */ bool db_map_equal(vm_map_t map1, vm_map_t map2) { return ((map1 == map2) || ((map1 == NULL) && (map2 == kernel_map)) || ((map1 == kernel_map) && (map2 == NULL))); } bool db_map_current(vm_map_t map) { #if 0 thread_t thread; return ((map == NULL) || (map == kernel_map) || (((thread = current_thread()) != NULL) && (map == thread->task->map))); #else return (true); #endif } vm_map_t db_map_addr(vm_offset_t addr) { #if 0 thread_t thread; /* * We want to return kernel_map for all * non-user addresses, even when debugging * kernel tasks with their own maps. */ if ((VM_MIN_ADDRESS <= addr) && (addr < VM_MAX_ADDRESS) && ((thread = current_thread()) != NULL)) return thread->task->map; else #endif return kernel_map; } Index: head/sys/ddb/db_output.c =================================================================== --- head/sys/ddb/db_output.c (revision 365226) +++ head/sys/ddb/db_output.c (revision 365227) @@ -1,396 +1,394 @@ /*- * SPDX-License-Identifier: MIT-CMU * * Mach Operating System * Copyright (c) 1991,1990 Carnegie Mellon University * All Rights Reserved. * * Permission to use, copy, modify and distribute this software and its * documentation is hereby granted, provided that both the copyright * notice and this permission notice appear in all copies of the * software, derivative works or modified versions, and any portions * thereof, and that both notices appear in supporting documentation. * * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. * * Carnegie Mellon requests users of this software to return to * * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU * School of Computer Science * Carnegie Mellon University * Pittsburgh PA 15213-3890 * * any improvements or extensions that they make and grant Carnegie the * rights to redistribute these changes. */ /* * Author: David B. Golub, Carnegie Mellon University * Date: 7/90 */ /* * Printf and character output for debugger. */ #include __FBSDID("$FreeBSD$"); #include "opt_ddb.h" #include #include #include #include #include #include #include #include #include struct dbputchar_arg { size_t da_nbufr; size_t da_remain; char *da_pbufr; char *da_pnext; }; /* * Character output - tracks position in line. * To do this correctly, we should know how wide * the output device is - then we could zero * the line position when the output device wraps * around to the start of the next line. * * Instead, we count the number of spaces printed * since the last printing character so that we * don't print trailing spaces. This avoids most * of the wraparounds. */ static int db_output_position = 0; /* output column */ static int db_last_non_space = 0; /* last non-space character */ db_expr_t db_tab_stop_width = 8; /* how wide are tab stops? */ #define NEXT_TAB(i) rounddown((i) + db_tab_stop_width, db_tab_stop_width) db_expr_t db_max_width = 79; /* output line width */ db_expr_t db_lines_per_page = 20; /* lines per page */ volatile int db_pager_quit; /* user requested quit */ static int db_newlines; /* # lines this page */ static int db_maxlines; /* max lines/page when paging */ static int ddb_use_printf = 0; SYSCTL_INT(_debug, OID_AUTO, ddb_use_printf, CTLFLAG_RW, &ddb_use_printf, 0, "use printf for all ddb output"); static void db_putc(int c); static void db_puts(const char *str); static void db_putchar(int c, void *arg); static void db_pager(void); /* * Force pending whitespace. */ void db_force_whitespace(void) { int last_print, next_tab; last_print = db_last_non_space; while (last_print < db_output_position) { next_tab = NEXT_TAB(last_print); if (next_tab <= db_output_position) { while (last_print < next_tab) { /* DON'T send a tab!!! */ cnputc(' '); db_capture_writech(' '); last_print++; } } else { cnputc(' '); db_capture_writech(' '); last_print++; } } db_last_non_space = db_output_position; } /* * Output character. Buffer whitespace. */ static void db_putchar(int c, void *arg) { struct dbputchar_arg *dap = arg; if (dap->da_pbufr == NULL) { - /* No bufferized output is provided. */ db_putc(c); } else { - *dap->da_pnext++ = c; dap->da_remain--; /* Leave always the buffer 0 terminated. */ *dap->da_pnext = '\0'; /* Check if the buffer needs to be flushed. */ if (dap->da_remain < 2 || c == '\n') { db_puts(dap->da_pbufr); dap->da_pnext = dap->da_pbufr; dap->da_remain = dap->da_nbufr; *dap->da_pnext = '\0'; } } } static void db_putc(int c) { /* * If not in the debugger or the user requests it, output data to * both the console and the message buffer. */ if (!kdb_active || ddb_use_printf) { printf("%c", c); if (!kdb_active) return; if (c == '\r' || c == '\n') db_check_interrupt(); if (c == '\n' && db_maxlines > 0) { db_newlines++; if (db_newlines >= db_maxlines) db_pager(); } return; } /* Otherwise, output data directly to the console. */ if (c > ' ' && c <= '~') { /* * Printing character. * If we have spaces to print, print them first. * Use tabs if possible. */ db_force_whitespace(); cnputc(c); db_capture_writech(c); db_output_position++; db_last_non_space = db_output_position; } else if (c == '\n') { /* Newline */ cnputc(c); db_capture_writech(c); db_output_position = 0; db_last_non_space = 0; db_check_interrupt(); if (db_maxlines > 0) { db_newlines++; if (db_newlines >= db_maxlines) db_pager(); } } else if (c == '\r') { /* Return */ cnputc(c); db_capture_writech(c); db_output_position = 0; db_last_non_space = 0; db_check_interrupt(); } else if (c == '\t') { /* assume tabs every 8 positions */ db_output_position = NEXT_TAB(db_output_position); } else if (c == ' ') { /* space */ db_output_position++; } else if (c == '\007') { /* bell */ cnputc(c); /* No need to beep in a log: db_capture_writech(c); */ } /* other characters are assumed non-printing */ } static void db_puts(const char *str) { int i; for (i = 0; str[i] != '\0'; i++) db_putc(str[i]); } /* * Turn on the pager. */ void db_enable_pager(void) { if (db_maxlines == 0) { db_maxlines = db_lines_per_page; db_newlines = 0; db_pager_quit = 0; } } /* * Turn off the pager. */ void db_disable_pager(void) { db_maxlines = 0; } /* * A simple paging callout function. It supports several simple more(1)-like * commands as well as a quit command that sets db_pager_quit which db * commands can poll to see if they should terminate early. */ void db_pager(void) { int c, done; db_capture_enterpager(); db_printf("--More--\r"); done = 0; while (!done) { c = cngetc(); switch (c) { case 'e': case 'j': case '\n': /* Just one more line. */ db_maxlines = 1; done++; break; case 'd': /* Half a page. */ db_maxlines = db_lines_per_page / 2; done++; break; case 'f': case ' ': /* Another page. */ db_maxlines = db_lines_per_page; done++; break; case 'q': case 'Q': case 'x': case 'X': /* Quit */ db_maxlines = 0; db_pager_quit = 1; done++; break; #if 0 /* FALLTHROUGH */ default: cnputc('\007'); #endif } } db_printf(" "); db_force_whitespace(); db_printf("\r"); db_newlines = 0; db_capture_exitpager(); } /* * Return output position */ int db_print_position(void) { return (db_output_position); } /* * Printing */ int db_printf(const char *fmt, ...) { #ifdef DDB_BUFR_SIZE char bufr[DDB_BUFR_SIZE]; #endif struct dbputchar_arg dca; va_list listp; int retval; #ifdef DDB_BUFR_SIZE dca.da_pbufr = bufr; dca.da_pnext = dca.da_pbufr; dca.da_nbufr = sizeof(bufr); dca.da_remain = sizeof(bufr); *dca.da_pnext = '\0'; #else dca.da_pbufr = NULL; #endif va_start(listp, fmt); retval = kvprintf (fmt, db_putchar, &dca, db_radix, listp); va_end(listp); #ifdef DDB_BUFR_SIZE if (*dca.da_pbufr != '\0') db_puts(dca.da_pbufr); #endif return (retval); } int db_indent; void db_iprintf(const char *fmt,...) { #ifdef DDB_BUFR_SIZE char bufr[DDB_BUFR_SIZE]; #endif struct dbputchar_arg dca; int i; va_list listp; for (i = db_indent; i >= 8; i -= 8) db_printf("\t"); while (--i >= 0) db_printf(" "); #ifdef DDB_BUFR_SIZE dca.da_pbufr = bufr; dca.da_pnext = dca.da_pbufr; dca.da_nbufr = sizeof(bufr); dca.da_remain = sizeof(bufr); *dca.da_pnext = '\0'; #else dca.da_pbufr = NULL; #endif va_start(listp, fmt); kvprintf (fmt, db_putchar, &dca, db_radix, listp); va_end(listp); #ifdef DDB_BUFR_SIZE if (*dca.da_pbufr != '\0') db_puts(dca.da_pbufr); #endif } /* * End line if too long. */ void db_end_line(int field_width) { if (db_output_position + field_width > db_max_width) db_printf("\n"); } Index: head/sys/ddb/db_ps.c =================================================================== --- head/sys/ddb/db_ps.c (revision 365226) +++ head/sys/ddb/db_ps.c (revision 365227) @@ -1,537 +1,537 @@ /*- * SPDX-License-Identifier: BSD-3-Clause * * Copyright (c) 1993 The Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include "opt_kstack_pages.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #define PRINT_NONE 0 #define PRINT_ARGS 1 static void dumpthread(volatile struct proc *p, volatile struct thread *td, int all); static void db_ps_proc(struct proc *p); static int ps_mode; /* * At least one non-optional show-command must be implemented using * DB_SHOW_ALL_COMMAND() so that db_show_all_cmd_set gets created. * Here is one. */ DB_SHOW_ALL_COMMAND(procs, db_procs_cmd) { db_ps(addr, have_addr, count, modif); } static void dump_args(volatile struct proc *p) { char *args; int i, len; if (p->p_args == NULL) return; args = p->p_args->ar_args; len = (int)p->p_args->ar_length; for (i = 0; i < len; i++) { if (args[i] == '\0') db_printf(" "); else db_printf("%c", args[i]); } } /* * Layout: * - column counts * - header * - single-threaded process * - multi-threaded process * - thread in a MT process * * 1 2 3 4 5 6 7 * 1234567890123456789012345678901234567890123456789012345678901234567890 * pid ppid pgrp uid state wmesg wchan cmd * * (threaded) * * * For machines with 64-bit pointers, we expand the wchan field 8 more * characters. */ void db_ps(db_expr_t addr, bool hasaddr, db_expr_t count, char *modif) { struct proc *p; int i, j; ps_mode = modif[0] == 'a' ? PRINT_ARGS : PRINT_NONE; #ifdef __LP64__ db_printf(" pid ppid pgrp uid state wmesg wchan cmd\n"); #else db_printf(" pid ppid pgrp uid state wmesg wchan cmd\n"); #endif if (!LIST_EMPTY(&allproc)) p = LIST_FIRST(&allproc); else p = &proc0; for (; p != NULL && !db_pager_quit; p = LIST_NEXT(p, p_list)) db_ps_proc(p); /* * Do zombies. */ for (i = 0; i < pidhashlock + 1 && !db_pager_quit; i++) { for (j = i; j <= pidhash && !db_pager_quit; j += pidhashlock + 1) { LIST_FOREACH(p, &pidhashtbl[j], p_hash) { if (p->p_state == PRS_ZOMBIE) db_ps_proc(p); } } } } static void db_ps_proc(struct proc *p) { volatile struct proc *pp; volatile struct thread *td; struct ucred *cred; struct pgrp *pgrp; char state[9]; int rflag, sflag, dflag, lflag, wflag; pp = p->p_pptr; if (pp == NULL) pp = p; cred = p->p_ucred; pgrp = p->p_pgrp; db_printf("%5d %5d %5d %5d ", p->p_pid, pp->p_pid, pgrp != NULL ? pgrp->pg_id : 0, cred != NULL ? cred->cr_ruid : 0); /* Determine our primary process state. */ switch (p->p_state) { case PRS_NORMAL: if (P_SHOULDSTOP(p)) state[0] = 'T'; else { /* * One of D, L, R, S, W. For a * multithreaded process we will use * the state of the thread with the * highest precedence. The * precendence order from high to low * is R, L, D, S, W. If no thread is * in a sane state we use '?' for our * primary state. */ rflag = sflag = dflag = lflag = wflag = 0; FOREACH_THREAD_IN_PROC(p, td) { if (td->td_state == TDS_RUNNING || td->td_state == TDS_RUNQ || td->td_state == TDS_CAN_RUN) rflag++; if (TD_ON_LOCK(td)) lflag++; if (TD_IS_SLEEPING(td)) { if (!(td->td_flags & TDF_SINTR)) dflag++; else sflag++; } if (TD_AWAITING_INTR(td)) wflag++; } if (rflag) state[0] = 'R'; else if (lflag) state[0] = 'L'; else if (dflag) state[0] = 'D'; else if (sflag) state[0] = 'S'; else if (wflag) state[0] = 'W'; else state[0] = '?'; } break; case PRS_NEW: state[0] = 'N'; break; case PRS_ZOMBIE: state[0] = 'Z'; break; default: state[0] = 'U'; break; } state[1] = '\0'; /* Additional process state flags. */ if (!(p->p_flag & P_INMEM)) strlcat(state, "W", sizeof(state)); if (p->p_flag & P_TRACED) strlcat(state, "X", sizeof(state)); if (p->p_flag & P_WEXIT && p->p_state != PRS_ZOMBIE) strlcat(state, "E", sizeof(state)); if (p->p_flag & P_PPWAIT) strlcat(state, "V", sizeof(state)); if (p->p_flag & P_SYSTEM || p->p_lock > 0) strlcat(state, "L", sizeof(state)); if (p->p_pgrp != NULL && p->p_session != NULL && SESS_LEADER(p)) strlcat(state, "s", sizeof(state)); /* Cheated here and didn't compare pgid's. */ if (p->p_flag & P_CONTROLT) strlcat(state, "+", sizeof(state)); if (cred != NULL && jailed(cred)) strlcat(state, "J", sizeof(state)); db_printf(" %-6.6s ", state); if (p->p_flag & P_HADTHREADS) { #ifdef __LP64__ db_printf(" (threaded) "); #else db_printf(" (threaded) "); #endif if (p->p_flag & P_SYSTEM) db_printf("["); db_printf("%s", p->p_comm); if (p->p_flag & P_SYSTEM) db_printf("]"); if (ps_mode == PRINT_ARGS) { db_printf(" "); dump_args(p); } db_printf("\n"); } FOREACH_THREAD_IN_PROC(p, td) { dumpthread(p, td, p->p_flag & P_HADTHREADS); if (db_pager_quit) break; } } static void dumpthread(volatile struct proc *p, volatile struct thread *td, int all) { char state[9], wprefix; const char *wmesg; const void *wchan; - + if (all) { db_printf("%6d ", td->td_tid); switch (td->td_state) { case TDS_RUNNING: snprintf(state, sizeof(state), "Run"); break; case TDS_RUNQ: snprintf(state, sizeof(state), "RunQ"); break; case TDS_CAN_RUN: snprintf(state, sizeof(state), "CanRun"); break; case TDS_INACTIVE: snprintf(state, sizeof(state), "Inactv"); break; case TDS_INHIBITED: state[0] = '\0'; if (TD_ON_LOCK(td)) strlcat(state, "L", sizeof(state)); if (TD_IS_SLEEPING(td)) { if (td->td_flags & TDF_SINTR) strlcat(state, "S", sizeof(state)); else strlcat(state, "D", sizeof(state)); } if (TD_IS_SWAPPED(td)) strlcat(state, "W", sizeof(state)); if (TD_AWAITING_INTR(td)) strlcat(state, "I", sizeof(state)); if (TD_IS_SUSPENDED(td)) strlcat(state, "s", sizeof(state)); if (state[0] != '\0') break; default: snprintf(state, sizeof(state), "???"); } db_printf(" %-6.6s ", state); } wprefix = ' '; if (TD_ON_LOCK(td)) { wprefix = '*'; wmesg = td->td_lockname; wchan = td->td_blocked; } else if (TD_ON_SLEEPQ(td)) { wmesg = td->td_wmesg; wchan = td->td_wchan; } else if (TD_IS_RUNNING(td)) { snprintf(state, sizeof(state), "CPU %d", td->td_oncpu); wmesg = state; wchan = NULL; } else { wmesg = ""; wchan = NULL; } db_printf("%c%-7.7s ", wprefix, wmesg); if (wchan == NULL) #ifdef __LP64__ db_printf("%18s ", ""); #else db_printf("%10s ", ""); #endif else db_printf("%p ", wchan); if (p->p_flag & P_SYSTEM) db_printf("["); if (td->td_name[0] != '\0') db_printf("%s", td->td_name); else db_printf("%s", td->td_proc->p_comm); if (p->p_flag & P_SYSTEM) db_printf("]"); if (ps_mode == PRINT_ARGS && all == 0) { db_printf(" "); dump_args(p); } db_printf("\n"); } DB_SHOW_COMMAND(thread, db_show_thread) { struct thread *td; struct lock_object *lock; u_int delta; bool comma; /* Determine which thread to examine. */ if (have_addr) td = db_lookup_thread(addr, false); else td = kdb_thread; lock = (struct lock_object *)td->td_lock; db_printf("Thread %d at %p:\n", td->td_tid, td); db_printf(" proc (pid %d): %p\n", td->td_proc->p_pid, td->td_proc); if (td->td_name[0] != '\0') db_printf(" name: %s\n", td->td_name); db_printf(" pcb: %p\n", td->td_pcb); db_printf(" stack: %p-%p\n", (void *)td->td_kstack, (void *)(td->td_kstack + td->td_kstack_pages * PAGE_SIZE - 1)); db_printf(" flags: %#x ", td->td_flags); db_printf(" pflags: %#x\n", td->td_pflags); db_printf(" state: "); switch (td->td_state) { case TDS_INACTIVE: db_printf("INACTIVE\n"); break; case TDS_CAN_RUN: db_printf("CAN RUN\n"); break; case TDS_RUNQ: db_printf("RUNQ\n"); break; case TDS_RUNNING: db_printf("RUNNING (CPU %d)\n", td->td_oncpu); break; case TDS_INHIBITED: db_printf("INHIBITED: {"); comma = false; if (TD_IS_SLEEPING(td)) { db_printf("SLEEPING"); comma = true; } if (TD_IS_SUSPENDED(td)) { if (comma) db_printf(", "); db_printf("SUSPENDED"); comma = true; } if (TD_IS_SWAPPED(td)) { if (comma) db_printf(", "); db_printf("SWAPPED"); comma = true; } if (TD_ON_LOCK(td)) { if (comma) db_printf(", "); db_printf("LOCK"); comma = true; } if (TD_AWAITING_INTR(td)) { if (comma) db_printf(", "); db_printf("IWAIT"); } db_printf("}\n"); break; default: db_printf("??? (%#x)\n", td->td_state); break; } if (TD_ON_LOCK(td)) db_printf(" lock: %s turnstile: %p\n", td->td_lockname, td->td_blocked); if (TD_ON_SLEEPQ(td)) db_printf( " wmesg: %s wchan: %p sleeptimo %lx. %jx (curr %lx. %jx)\n", td->td_wmesg, td->td_wchan, (long)sbttobt(td->td_sleeptimo).sec, (uintmax_t)sbttobt(td->td_sleeptimo).frac, (long)sbttobt(sbinuptime()).sec, (uintmax_t)sbttobt(sbinuptime()).frac); db_printf(" priority: %d\n", td->td_priority); db_printf(" container lock: %s (%p)\n", lock->lo_name, lock); if (td->td_swvoltick != 0) { delta = ticks - td->td_swvoltick; db_printf(" last voluntary switch: %u.%03u s ago\n", delta / hz, (delta % hz) * 1000 / hz); } if (td->td_swinvoltick != 0) { delta = ticks - td->td_swinvoltick; db_printf(" last involuntary switch: %u.%03u s ago\n", delta / hz, (delta % hz) * 1000 / hz); } } DB_SHOW_COMMAND(proc, db_show_proc) { struct thread *td; struct proc *p; int i; /* Determine which process to examine. */ if (have_addr) p = db_lookup_proc(addr); else p = kdb_thread->td_proc; db_printf("Process %d (%s) at %p:\n", p->p_pid, p->p_comm, p); db_printf(" state: "); switch (p->p_state) { case PRS_NEW: db_printf("NEW\n"); break; case PRS_NORMAL: db_printf("NORMAL\n"); break; case PRS_ZOMBIE: db_printf("ZOMBIE\n"); break; default: db_printf("??? (%#x)\n", p->p_state); } if (p->p_ucred != NULL) { db_printf(" uid: %d gids: ", p->p_ucred->cr_uid); for (i = 0; i < p->p_ucred->cr_ngroups; i++) { db_printf("%d", p->p_ucred->cr_groups[i]); if (i < (p->p_ucred->cr_ngroups - 1)) db_printf(", "); } db_printf("\n"); } if (p->p_pptr != NULL) db_printf(" parent: pid %d at %p\n", p->p_pptr->p_pid, p->p_pptr); if (p->p_leader != NULL && p->p_leader != p) db_printf(" leader: pid %d at %p\n", p->p_leader->p_pid, p->p_leader); if (p->p_sysent != NULL) db_printf(" ABI: %s\n", p->p_sysent->sv_name); if (p->p_args != NULL) { db_printf(" arguments: "); dump_args(p); db_printf("\n"); } db_printf(" reaper: %p reapsubtree: %d\n", p->p_reaper, p->p_reapsubtree); db_printf(" sigparent: %d\n", p->p_sigparent); db_printf(" vmspace: %p\n", p->p_vmspace); db_printf(" (map %p)\n", (p->p_vmspace != NULL) ? &p->p_vmspace->vm_map : 0); db_printf(" (map.pmap %p)\n", (p->p_vmspace != NULL) ? &p->p_vmspace->vm_map.pmap : 0); db_printf(" (pmap %p)\n", (p->p_vmspace != NULL) ? &p->p_vmspace->vm_pmap : 0); db_printf(" threads: %d\n", p->p_numthreads); FOREACH_THREAD_IN_PROC(p, td) { dumpthread(p, td, 1); if (db_pager_quit) break; } } void db_findstack_cmd(db_expr_t addr, bool have_addr, db_expr_t dummy3 __unused, char *dummy4 __unused) { struct proc *p; struct thread *td; vm_offset_t saddr; if (have_addr) saddr = addr; else { db_printf("Usage: findstack
\n"); return; } FOREACH_PROC_IN_SYSTEM(p) { FOREACH_THREAD_IN_PROC(p, td) { if (td->td_kstack <= saddr && saddr < td->td_kstack + PAGE_SIZE * td->td_kstack_pages) { db_printf("Thread %p\n", td); return; } } } } Index: head/sys/ddb/db_sym.c =================================================================== --- head/sys/ddb/db_sym.c (revision 365226) +++ head/sys/ddb/db_sym.c (revision 365227) @@ -1,472 +1,470 @@ /*- * SPDX-License-Identifier: MIT-CMU * * Mach Operating System * Copyright (c) 1991,1990 Carnegie Mellon University * All Rights Reserved. * * Permission to use, copy, modify and distribute this software and its * documentation is hereby granted, provided that both the copyright * notice and this permission notice appear in all copies of the * software, derivative works or modified versions, and any portions * thereof, and that both notices appear in supporting documentation. * * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. * * Carnegie Mellon requests users of this software to return to * * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU * School of Computer Science * Carnegie Mellon University * Pittsburgh PA 15213-3890 * * any improvements or extensions that they make and grant Carnegie the * rights to redistribute these changes. */ /* * Author: David B. Golub, Carnegie Mellon University * Date: 7/90 */ #include __FBSDID("$FreeBSD$"); #include "opt_kstack_pages.h" #include #include #include #include #include #include #include #include #include "opt_ddb.h" /* * Multiple symbol tables */ #ifndef MAXNOSYMTABS #define MAXNOSYMTABS 3 /* mach, ux, emulator */ #endif static db_symtab_t db_symtabs[MAXNOSYMTABS] = {{0,},}; static int db_nsymtab = 0; static db_symtab_t *db_last_symtab; /* where last symbol was found */ static c_db_sym_t db_lookup( const char *symstr); static char *db_qualify(c_db_sym_t sym, char *symtabname); static bool db_symbol_is_ambiguous(c_db_sym_t sym); static bool db_line_at_pc(c_db_sym_t, char **, int *, db_expr_t); static int db_cpu = -1; #ifdef VIMAGE static void *db_vnet = NULL; #endif /* * Validate the CPU number used to interpret per-CPU variables so we can * avoid later confusion if an invalid CPU is requested. */ int db_var_db_cpu(struct db_variable *vp, db_expr_t *valuep, int op) { switch (op) { case DB_VAR_GET: *valuep = db_cpu; return (1); case DB_VAR_SET: if (*(int *)valuep < -1 || *(int *)valuep > mp_maxid) { db_printf("Invalid value: %d\n", *(int*)valuep); return (0); } db_cpu = *(int *)valuep; return (1); default: db_printf("db_var_db_cpu: unknown operation\n"); return (0); } } /* * Read-only variable reporting the current CPU, which is what we use when * db_cpu is set to -1. */ int db_var_curcpu(struct db_variable *vp, db_expr_t *valuep, int op) { switch (op) { case DB_VAR_GET: *valuep = curcpu; return (1); case DB_VAR_SET: db_printf("Read-only variable.\n"); return (0); default: db_printf("db_var_curcpu: unknown operation\n"); return (0); } } #ifdef VIMAGE /* * Validate the virtual network pointer used to interpret per-vnet global * variable expansion. Right now we don't do much here, really we should * walk the global vnet list to check it's an OK pointer. */ int db_var_db_vnet(struct db_variable *vp, db_expr_t *valuep, int op) { switch (op) { case DB_VAR_GET: *valuep = (db_expr_t)db_vnet; return (1); case DB_VAR_SET: db_vnet = *(void **)valuep; return (1); default: db_printf("db_var_db_vnet: unknown operation\n"); return (0); } } /* * Read-only variable reporting the current vnet, which is what we use when * db_vnet is set to NULL. */ int db_var_curvnet(struct db_variable *vp, db_expr_t *valuep, int op) { switch (op) { case DB_VAR_GET: *valuep = (db_expr_t)curvnet; return (1); case DB_VAR_SET: db_printf("Read-only variable.\n"); return (0); default: db_printf("db_var_curvnet: unknown operation\n"); return (0); } } #endif /* * Add symbol table, with given name, to list of symbol tables. */ void db_add_symbol_table(char *start, char *end, char *name, char *ref) { if (db_nsymtab >= MAXNOSYMTABS) { printf ("No slots left for %s symbol table", name); panic ("db_sym.c: db_add_symbol_table"); } db_symtabs[db_nsymtab].start = start; db_symtabs[db_nsymtab].end = end; db_symtabs[db_nsymtab].name = name; db_symtabs[db_nsymtab].private = ref; db_nsymtab++; } /* * db_qualify("vm_map", "ux") returns "unix:vm_map". * * Note: return value points to static data whose content is * overwritten by each call... but in practice this seems okay. */ static char * db_qualify(c_db_sym_t sym, char *symtabname) { const char *symname; static char tmp[256]; db_symbol_values(sym, &symname, 0); snprintf(tmp, sizeof(tmp), "%s:%s", symtabname, symname); return tmp; } - bool db_eqname(const char *src, const char *dst, int c) { if (!strcmp(src, dst)) return (true); if (src[0] == c) return (!strcmp(src+1,dst)); return (false); } bool db_value_of_name(const char *name, db_expr_t *valuep) { c_db_sym_t sym; sym = db_lookup(name); if (sym == C_DB_SYM_NULL) return (false); db_symbol_values(sym, &name, valuep); return (true); } bool db_value_of_name_pcpu(const char *name, db_expr_t *valuep) { static char tmp[256]; db_expr_t value; c_db_sym_t sym; int cpu; if (db_cpu != -1) cpu = db_cpu; else cpu = curcpu; snprintf(tmp, sizeof(tmp), "pcpu_entry_%s", name); sym = db_lookup(tmp); if (sym == C_DB_SYM_NULL) return (false); db_symbol_values(sym, &name, &value); if (value < DPCPU_START || value >= DPCPU_STOP) return (false); *valuep = (db_expr_t)((uintptr_t)value + dpcpu_off[cpu]); return (true); } bool db_value_of_name_vnet(const char *name, db_expr_t *valuep) { #ifdef VIMAGE static char tmp[256]; db_expr_t value; c_db_sym_t sym; struct vnet *vnet; if (db_vnet != NULL) vnet = db_vnet; else vnet = curvnet; snprintf(tmp, sizeof(tmp), "vnet_entry_%s", name); sym = db_lookup(tmp); if (sym == C_DB_SYM_NULL) return (false); db_symbol_values(sym, &name, &value); if (value < VNET_START || value >= VNET_STOP) return (false); *valuep = (db_expr_t)((uintptr_t)value + vnet->vnet_data_base); return (true); #else return (false); #endif } /* * Lookup a symbol. * If the symbol has a qualifier (e.g., ux:vm_map), * then only the specified symbol table will be searched; * otherwise, all symbol tables will be searched. */ static c_db_sym_t db_lookup(const char *symstr) { c_db_sym_t sp; int i; int symtab_start = 0; int symtab_end = db_nsymtab; const char *cp; /* * Look for, remove, and remember any symbol table specifier. */ for (cp = symstr; *cp; cp++) { if (*cp == ':') { for (i = 0; i < db_nsymtab; i++) { int n = strlen(db_symtabs[i].name); if ( n == (cp - symstr) && strncmp(symstr, db_symtabs[i].name, n) == 0 ) { symtab_start = i; symtab_end = i + 1; break; } } if (i == db_nsymtab) { db_error("invalid symbol table name"); } symstr = cp+1; } } /* * Look in the specified set of symbol tables. * Return on first match. */ for (i = symtab_start; i < symtab_end; i++) { sp = X_db_lookup(&db_symtabs[i], symstr); if (sp) { db_last_symtab = &db_symtabs[i]; return sp; } } return 0; } /* * If true, check across symbol tables for multiple occurrences * of a name. Might slow things down quite a bit. */ static volatile bool db_qualify_ambiguous_names = false; /* * Does this symbol name appear in more than one symbol table? * Used by db_symbol_values to decide whether to qualify a symbol. */ static bool db_symbol_is_ambiguous(c_db_sym_t sym) { const char *sym_name; int i; bool found_once = false; if (!db_qualify_ambiguous_names) return (false); db_symbol_values(sym, &sym_name, 0); for (i = 0; i < db_nsymtab; i++) { if (X_db_lookup(&db_symtabs[i], sym_name)) { if (found_once) return (true); found_once = true; } } return (false); } /* * Find the closest symbol to val, and return its name * and the difference between val and the symbol found. */ c_db_sym_t db_search_symbol(db_addr_t val, db_strategy_t strategy, db_expr_t *offp) { unsigned int diff; size_t newdiff; int i; c_db_sym_t ret = C_DB_SYM_NULL, sym; newdiff = diff = val; for (i = 0; i < db_nsymtab; i++) { sym = X_db_search_symbol(&db_symtabs[i], val, strategy, &newdiff); if ((uintmax_t)newdiff < (uintmax_t)diff) { db_last_symtab = &db_symtabs[i]; diff = newdiff; ret = sym; } } *offp = diff; return ret; } /* * Return name and value of a symbol */ void db_symbol_values(c_db_sym_t sym, const char **namep, db_expr_t *valuep) { db_expr_t value; if (sym == DB_SYM_NULL) { *namep = NULL; return; } X_db_symbol_values(db_last_symtab, sym, namep, &value); if (db_symbol_is_ambiguous(sym)) *namep = db_qualify(sym, db_last_symtab->name); if (valuep) *valuep = value; } - /* * Print a the closest symbol to value * * After matching the symbol according to the given strategy * we print it in the name+offset format, provided the symbol's * value is close enough (eg smaller than db_maxoff). * We also attempt to print [filename:linenum] when applicable * (eg for procedure names). * * If we could not find a reasonable name+offset representation, * then we just print the value in hex. Small values might get * bogus symbol associations, e.g. 3 might get some absolute * value like _INCLUDE_VERSION or something, therefore we do * not accept symbols whose value is "small" (and use plain hex). */ db_expr_t db_maxoff = 0x10000; void db_printsym(db_expr_t off, db_strategy_t strategy) { db_expr_t d; char *filename; const char *name; int linenum; c_db_sym_t cursym; if (off < 0 && off >= -db_maxoff) { db_printf("%+#lr", (long)off); return; } cursym = db_search_symbol(off, strategy, &d); db_symbol_values(cursym, &name, NULL); if (name == NULL || d >= (db_addr_t)db_maxoff) { db_printf("%#lr", (unsigned long)off); return; } #ifdef DDB_NUMSYM db_printf("%#lr = %s", (unsigned long)off, name); #else db_printf("%s", name); #endif if (d) db_printf("+%+#lr", (long)d); if (strategy == DB_STGY_PROC) { if (db_line_at_pc(cursym, &filename, &linenum, off)) db_printf(" [%s:%d]", filename, linenum); } } static bool db_line_at_pc(c_db_sym_t sym, char **filename, int *linenum, db_expr_t pc) { return (X_db_line_at_pc(db_last_symtab, sym, filename, linenum, pc)); } bool db_sym_numargs(c_db_sym_t sym, int *nargp, char **argnames) { return (X_db_sym_numargs(db_last_symtab, sym, nargp, argnames)); } Index: head/sys/ddb/db_watch.c =================================================================== --- head/sys/ddb/db_watch.c (revision 365226) +++ head/sys/ddb/db_watch.c (revision 365227) @@ -1,312 +1,310 @@ /*- * SPDX-License-Identifier: MIT-CMU * * Mach Operating System * Copyright (c) 1991,1990 Carnegie Mellon University * All Rights Reserved. * * Permission to use, copy, modify and distribute this software and its * documentation is hereby granted, provided that both the copyright * notice and this permission notice appear in all copies of the * software, derivative works or modified versions, and any portions * thereof, and that both notices appear in supporting documentation. * * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. * * Carnegie Mellon requests users of this software to return to * * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU * School of Computer Science * Carnegie Mellon University * Pittsburgh PA 15213-3890 * * any improvements or extensions that they make and grant Carnegie the * rights to redistribute these changes. */ /* * Author: Richard P. Draves, Carnegie Mellon University * Date: 10/90 */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include /* * Watchpoints. */ static bool db_watchpoints_inserted = true; #define NWATCHPOINTS 100 static struct db_watchpoint db_watch_table[NWATCHPOINTS]; static db_watchpoint_t db_next_free_watchpoint = &db_watch_table[0]; static db_watchpoint_t db_free_watchpoints = 0; static db_watchpoint_t db_watchpoint_list = 0; static db_watchpoint_t db_watchpoint_alloc(void); static void db_watchpoint_free(db_watchpoint_t watch); static void db_delete_watchpoint(vm_map_t map, db_addr_t addr); #ifdef notused static bool db_find_watchpoint(vm_map_t map, db_addr_t addr, db_regs_t *regs); #endif static void db_list_watchpoints(void); static void db_set_watchpoint(vm_map_t map, db_addr_t addr, vm_size_t size); static db_watchpoint_t db_watchpoint_alloc(void) { db_watchpoint_t watch; if ((watch = db_free_watchpoints) != 0) { db_free_watchpoints = watch->link; return (watch); } if (db_next_free_watchpoint == &db_watch_table[NWATCHPOINTS]) { db_printf("All watchpoints used.\n"); return (0); } watch = db_next_free_watchpoint; db_next_free_watchpoint++; return (watch); } static void db_watchpoint_free(db_watchpoint_t watch) { watch->link = db_free_watchpoints; db_free_watchpoints = watch; } static void db_set_watchpoint(vm_map_t map, db_addr_t addr, vm_size_t size) { db_watchpoint_t watch; if (map == NULL) { db_printf("No map.\n"); return; } /* * Should we do anything fancy with overlapping regions? */ for (watch = db_watchpoint_list; watch != 0; watch = watch->link) if (db_map_equal(watch->map, map) && (watch->loaddr == addr) && (watch->hiaddr == addr+size)) { db_printf("Already set.\n"); return; } watch = db_watchpoint_alloc(); if (watch == 0) { db_printf("Too many watchpoints.\n"); return; } watch->map = map; watch->loaddr = addr; watch->hiaddr = addr+size; watch->link = db_watchpoint_list; db_watchpoint_list = watch; db_watchpoints_inserted = false; } static void db_delete_watchpoint(vm_map_t map, db_addr_t addr) { db_watchpoint_t watch; db_watchpoint_t *prev; for (prev = &db_watchpoint_list; (watch = *prev) != 0; prev = &watch->link) if (db_map_equal(watch->map, map) && (watch->loaddr <= addr) && (addr < watch->hiaddr)) { *prev = watch->link; db_watchpoint_free(watch); return; } db_printf("Not set.\n"); } static void db_list_watchpoints(void) { db_watchpoint_t watch; if (db_watchpoint_list == 0) { db_printf("No watchpoints set\n"); return; } #ifdef __LP64__ db_printf(" Map Address Size\n"); #else db_printf(" Map Address Size\n"); #endif for (watch = db_watchpoint_list; watch != 0; watch = watch->link) #ifdef __LP64__ db_printf("%s%16p %16lx %lx\n", #else db_printf("%s%8p %8lx %lx\n", #endif db_map_current(watch->map) ? "*" : " ", (void *)watch->map, (long)watch->loaddr, (long)watch->hiaddr - (long)watch->loaddr); } /* Delete watchpoint */ /*ARGSUSED*/ void db_deletewatch_cmd(db_expr_t addr, bool have_addr, db_expr_t count, char *modif) { db_delete_watchpoint(db_map_addr(addr), addr); } /* Set watchpoint */ /*ARGSUSED*/ void db_watchpoint_cmd(db_expr_t addr, bool have_addr, db_expr_t count, char *modif) { vm_size_t size; db_expr_t value; if (db_expression(&value)) size = (vm_size_t) value; else size = 4; db_skip_to_eol(); db_set_watchpoint(db_map_addr(addr), addr, size); } /* * At least one non-optional show-command must be implemented using * DB_SHOW_COMMAND() so that db_show_cmd_set gets created. Here is one. */ DB_SHOW_COMMAND(watches, db_listwatch_cmd) { db_list_watchpoints(); db_md_list_watchpoints(); } void db_set_watchpoints(void) { db_watchpoint_t watch; if (!db_watchpoints_inserted) { for (watch = db_watchpoint_list; watch != 0; watch = watch->link) pmap_protect(watch->map->pmap, trunc_page(watch->loaddr), round_page(watch->hiaddr), VM_PROT_READ); db_watchpoints_inserted = true; } } void db_clear_watchpoints(void) { db_watchpoints_inserted = false; } #ifdef notused static bool db_find_watchpoint(vm_map_t map, db_addr_t addr, db_regs_t regs) { db_watchpoint_t watch; db_watchpoint_t found = 0; for (watch = db_watchpoint_list; watch != 0; watch = watch->link) if (db_map_equal(watch->map, map)) { if ((watch->loaddr <= addr) && (addr < watch->hiaddr)) return (true); else if ((trunc_page(watch->loaddr) <= addr) && (addr < round_page(watch->hiaddr))) found = watch; } /* * We didn't hit exactly on a watchpoint, but we are * in a protected region. We want to single-step * and then re-protect. */ if (found) { db_watchpoints_inserted = false; db_single_step(regs); } return (false); } #endif - - /* Delete hardware watchpoint */ /*ARGSUSED*/ void db_deletehwatch_cmd(db_expr_t addr, bool have_addr, db_expr_t count, char *modif) { int rc; if (count < 0) count = 4; rc = db_md_clr_watchpoint(addr, count); if (rc < 0) db_printf("hardware watchpoint could not be deleted\n"); } /* Set hardware watchpoint */ /*ARGSUSED*/ void db_hwatchpoint_cmd(db_expr_t addr, bool have_addr, db_expr_t count, char *modif) { int rc; if (count < 0) count = 4; rc = db_md_set_watchpoint(addr, count); if (rc < 0) db_printf("hardware watchpoint could not be set\n"); } Index: head/sys/ddb/db_write_cmd.c =================================================================== --- head/sys/ddb/db_write_cmd.c (revision 365226) +++ head/sys/ddb/db_write_cmd.c (revision 365227) @@ -1,93 +1,92 @@ /*- * SPDX-License-Identifier: MIT-CMU * * Mach Operating System * Copyright (c) 1991,1990 Carnegie Mellon University * All Rights Reserved. * * Permission to use, copy, modify and distribute this software and its * documentation is hereby granted, provided that both the copyright * notice and this permission notice appear in all copies of the * software, derivative works or modified versions, and any portions * thereof, and that both notices appear in supporting documentation. * * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. * * Carnegie Mellon requests users of this software to return to * * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU * School of Computer Science * Carnegie Mellon University * Pittsburgh PA 15213-3890 * * any improvements or extensions that they make and grant Carnegie the * rights to redistribute these changes. */ /* * Author: David B. Golub, Carnegie Mellon University * Date: 7/90 */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include /* * Write to file. */ /*ARGSUSED*/ void db_write_cmd(db_expr_t address, bool have_addr, db_expr_t count, char * modif) { db_addr_t addr; db_expr_t old_value; db_expr_t new_value; int size; bool wrote_one = false; addr = (db_addr_t) address; switch (modif[0]) { case 'b': size = 1; break; case 'h': size = 2; break; case 'l': case '\0': size = 4; break; default: db_error("Unknown size\n"); return; } while (db_expression(&new_value)) { old_value = db_get_value(addr, size, false); db_printsym(addr, DB_STGY_ANY); db_printf("\t\t%#8lr\t=\t%#8lr\n", (long)old_value,(long)new_value); db_put_value(addr, size, new_value); addr += size; wrote_one = true; } if (!wrote_one) db_error("Nothing written.\n"); db_next = addr; db_prev = addr - size; db_skip_to_eol(); } -