1 1.38 ad /* $NetBSD: db_output.c,v 1.38 2023/10/07 20:22:53 ad Exp $ */ 2 1.7 cgd 3 1.27 simonb /* 4 1.1 cgd * Mach Operating System 5 1.1 cgd * Copyright (c) 1991,1990 Carnegie Mellon University 6 1.1 cgd * All Rights Reserved. 7 1.27 simonb * 8 1.1 cgd * Permission to use, copy, modify and distribute this software and its 9 1.1 cgd * documentation is hereby granted, provided that both the copyright 10 1.1 cgd * notice and this permission notice appear in all copies of the 11 1.1 cgd * software, derivative works or modified versions, and any portions 12 1.1 cgd * thereof, and that both notices appear in supporting documentation. 13 1.27 simonb * 14 1.19 pk * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 15 1.1 cgd * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR 16 1.1 cgd * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 17 1.27 simonb * 18 1.1 cgd * Carnegie Mellon requests users of this software to return to 19 1.27 simonb * 20 1.1 cgd * Software Distribution Coordinator or Software.Distribution (at) CS.CMU.EDU 21 1.1 cgd * School of Computer Science 22 1.1 cgd * Carnegie Mellon University 23 1.1 cgd * Pittsburgh PA 15213-3890 24 1.27 simonb * 25 1.1 cgd * any improvements or extensions that they make and grant Carnegie the 26 1.1 cgd * rights to redistribute these changes. 27 1.1 cgd */ 28 1.1 cgd 29 1.1 cgd /* 30 1.1 cgd * Printf and character output for debugger. 31 1.1 cgd */ 32 1.26 lukem 33 1.33 matt #ifdef _KERNEL_OPT 34 1.32 matt #include "opt_ddbparam.h" 35 1.33 matt #endif 36 1.32 matt 37 1.26 lukem #include <sys/cdefs.h> 38 1.38 ad __KERNEL_RCSID(0, "$NetBSD: db_output.c,v 1.38 2023/10/07 20:22:53 ad Exp $"); 39 1.26 lukem 40 1.6 mycroft #include <sys/param.h> 41 1.16 cgd #include <sys/systm.h> 42 1.31 joerg #include <sys/stdarg.h> 43 1.38 ad #include <sys/time.h> 44 1.1 cgd 45 1.10 christos #include <dev/cons.h> 46 1.10 christos 47 1.30 ad #include <ddb/ddb.h> 48 1.10 christos 49 1.1 cgd /* 50 1.1 cgd * Character output - tracks position in line. 51 1.1 cgd * To do this correctly, we should know how wide 52 1.1 cgd * the output device is - then we could zero 53 1.1 cgd * the line position when the output device wraps 54 1.1 cgd * around to the start of the next line. 55 1.1 cgd * 56 1.1 cgd * Instead, we count the number of spaces printed 57 1.1 cgd * since the last printing character so that we 58 1.1 cgd * don't print trailing spaces. This avoids most 59 1.1 cgd * of the wraparounds. 60 1.1 cgd */ 61 1.4 brezak 62 1.4 brezak #ifndef DB_MAX_LINE 63 1.4 brezak #define DB_MAX_LINE 24 /* maximum line */ 64 1.25 mrg #endif /* DB_MAX_LINE */ 65 1.25 mrg #ifndef DB_MAX_WIDTH 66 1.4 brezak #define DB_MAX_WIDTH 80 /* maximum width */ 67 1.25 mrg #endif /* DB_MAX_WIDTH */ 68 1.4 brezak 69 1.4 brezak #define DB_MIN_MAX_WIDTH 20 /* minimum max width */ 70 1.4 brezak #define DB_MIN_MAX_LINE 3 /* minimum max line */ 71 1.4 brezak #define CTRL(c) ((c) & 0xff) 72 1.4 brezak 73 1.27 simonb int db_output_line = 0; /* output line number */ 74 1.27 simonb int db_tab_stop_width = 8; /* how wide are tab stops? */ 75 1.27 simonb int db_max_line = DB_MAX_LINE; /* output max lines */ 76 1.27 simonb int db_max_width = DB_MAX_WIDTH; /* output line width */ 77 1.27 simonb 78 1.27 simonb static int db_output_position = 0; /* output column */ 79 1.27 simonb static int db_last_non_space = 0; /* last non-space character */ 80 1.1 cgd 81 1.27 simonb static void db_more(void); 82 1.1 cgd 83 1.1 cgd /* 84 1.1 cgd * Force pending whitespace. 85 1.1 cgd */ 86 1.1 cgd void 87 1.27 simonb db_force_whitespace(void) 88 1.1 cgd { 89 1.22 augustss int last_print, next_tab; 90 1.1 cgd 91 1.1 cgd last_print = db_last_non_space; 92 1.1 cgd while (last_print < db_output_position) { 93 1.27 simonb next_tab = DB_NEXT_TAB(last_print); 94 1.27 simonb if (next_tab <= db_output_position) { 95 1.27 simonb while (last_print < next_tab) { /* DON'T send a tab!! */ 96 1.27 simonb cnputc(' '); 97 1.27 simonb last_print++; 98 1.27 simonb } 99 1.27 simonb } else { 100 1.2 cgd cnputc(' '); 101 1.2 cgd last_print++; 102 1.2 cgd } 103 1.1 cgd } 104 1.1 cgd db_last_non_space = db_output_position; 105 1.1 cgd } 106 1.1 cgd 107 1.35 uwe 108 1.35 uwe /* 109 1.36 uwe * End the current line if it exceeds $maxwidth 110 1.35 uwe */ 111 1.35 uwe static void 112 1.35 uwe db_check_wrap(void) 113 1.35 uwe { 114 1.35 uwe 115 1.35 uwe if (db_max_width >= DB_MIN_MAX_WIDTH 116 1.35 uwe && db_output_position >= db_max_width) { 117 1.35 uwe cnputc('\n'); 118 1.35 uwe db_output_position = 0; 119 1.35 uwe db_last_non_space = 0; 120 1.35 uwe db_output_line++; 121 1.35 uwe } 122 1.35 uwe } 123 1.35 uwe 124 1.35 uwe 125 1.4 brezak static void 126 1.27 simonb db_more(void) 127 1.4 brezak { 128 1.28 christos const char *p; 129 1.4 brezak int quit_output = 0; 130 1.4 brezak 131 1.4 brezak for (p = "--db_more--"; *p; p++) 132 1.27 simonb cnputc(*p); 133 1.34 mrg switch (cngetc()) { 134 1.4 brezak case ' ': 135 1.27 simonb db_output_line = 0; 136 1.27 simonb break; 137 1.4 brezak case 'q': 138 1.4 brezak case CTRL('c'): 139 1.27 simonb db_output_line = 0; 140 1.27 simonb quit_output = 1; 141 1.27 simonb break; 142 1.4 brezak default: 143 1.27 simonb db_output_line--; 144 1.27 simonb break; 145 1.4 brezak } 146 1.4 brezak p = "\b\b\b\b\b\b\b\b\b\b\b \b\b\b\b\b\b\b\b\b\b\b"; 147 1.4 brezak while (*p) 148 1.27 simonb cnputc(*p++); 149 1.4 brezak if (quit_output) { 150 1.27 simonb db_error(0); 151 1.27 simonb /* NOTREACHED */ 152 1.4 brezak } 153 1.4 brezak } 154 1.4 brezak 155 1.1 cgd /* 156 1.1 cgd * Output character. Buffer whitespace. 157 1.1 cgd */ 158 1.10 christos void 159 1.27 simonb db_putchar(int c) 160 1.1 cgd { 161 1.4 brezak if (db_max_line >= DB_MIN_MAX_LINE && db_output_line >= db_max_line-1) 162 1.27 simonb db_more(); 163 1.1 cgd if (c > ' ' && c <= '~') { 164 1.27 simonb /* 165 1.27 simonb * Printing character. 166 1.27 simonb * If we have spaces to print, print them first. 167 1.27 simonb * Use tabs if possible. 168 1.27 simonb */ 169 1.27 simonb db_force_whitespace(); 170 1.35 uwe db_check_wrap(); 171 1.27 simonb cnputc(c); 172 1.27 simonb db_output_position++; 173 1.35 uwe db_check_wrap(); 174 1.27 simonb db_last_non_space = db_output_position; 175 1.27 simonb } else if (c == '\n') { 176 1.27 simonb /* Return */ 177 1.27 simonb cnputc(c); 178 1.4 brezak db_output_position = 0; 179 1.4 brezak db_last_non_space = 0; 180 1.4 brezak db_output_line++; 181 1.27 simonb db_check_interrupt(); 182 1.27 simonb } else if (c == '\t') { 183 1.27 simonb /* assume tabs every 8 positions */ 184 1.27 simonb db_output_position = DB_NEXT_TAB(db_output_position); 185 1.27 simonb } else if (c == ' ') { 186 1.27 simonb /* space */ 187 1.27 simonb db_output_position++; 188 1.27 simonb } else if (c == '\007') { 189 1.27 simonb /* bell */ 190 1.27 simonb cnputc(c); 191 1.1 cgd } 192 1.1 cgd /* other characters are assumed non-printing */ 193 1.1 cgd } 194 1.1 cgd 195 1.1 cgd /* 196 1.1 cgd * Return output position 197 1.1 cgd */ 198 1.1 cgd int 199 1.27 simonb db_print_position(void) 200 1.1 cgd { 201 1.27 simonb 202 1.1 cgd return (db_output_position); 203 1.1 cgd } 204 1.1 cgd 205 1.1 cgd /* 206 1.4 brezak * End line if too long. 207 1.4 brezak */ 208 1.4 brezak void 209 1.27 simonb db_end_line(void) 210 1.4 brezak { 211 1.27 simonb 212 1.4 brezak if (db_output_position >= db_max_width) 213 1.27 simonb db_printf("\n"); 214 1.23 tv } 215 1.23 tv 216 1.23 tv /* 217 1.23 tv * Replacement for old '%r' kprintf format. 218 1.23 tv */ 219 1.23 tv void 220 1.27 simonb db_format_radix(char *buf, size_t bufsiz, quad_t val, int altflag) 221 1.23 tv { 222 1.23 tv const char *fmt; 223 1.23 tv 224 1.23 tv if (db_radix == 16) { 225 1.23 tv db_format_hex(buf, bufsiz, val, altflag); 226 1.23 tv return; 227 1.23 tv } 228 1.23 tv 229 1.23 tv if (db_radix == 8) 230 1.23 tv fmt = altflag ? "-%#qo" : "-%qo"; 231 1.23 tv else 232 1.23 tv fmt = altflag ? "-%#qu" : "-%qu"; 233 1.23 tv 234 1.23 tv if (val < 0) 235 1.23 tv val = -val; 236 1.23 tv else 237 1.23 tv ++fmt; 238 1.23 tv 239 1.23 tv snprintf(buf, bufsiz, fmt, val); 240 1.23 tv } 241 1.23 tv 242 1.23 tv /* 243 1.23 tv * Replacement for old '%z' kprintf format. 244 1.23 tv */ 245 1.23 tv void 246 1.27 simonb db_format_hex(char *buf, size_t bufsiz, quad_t val, int altflag) 247 1.23 tv { 248 1.23 tv /* Only use alternate form if val is nonzero. */ 249 1.23 tv const char *fmt = (altflag && val) ? "-%#qx" : "-%qx"; 250 1.23 tv 251 1.23 tv if (val < 0) 252 1.23 tv val = -val; 253 1.23 tv else 254 1.23 tv ++fmt; 255 1.23 tv 256 1.23 tv snprintf(buf, bufsiz, fmt, val); 257 1.1 cgd } 258 1.37 ad 259 1.37 ad /* 260 1.37 ad * Print out a timespec value. 261 1.37 ad */ 262 1.37 ad void 263 1.37 ad db_print_timespec(struct timespec *ts) 264 1.37 ad { 265 1.37 ad 266 1.37 ad db_printf("%" PRIu64 ".%09ld", (uint64_t)ts->tv_sec, ts->tv_nsec); 267 1.37 ad } 268