hexdump.c revision 14774
1/*- 2 * Copyright (c) 1986, 1988, 1991, 1993 3 * The Regents of the University of California. All rights reserved. 4 * (c) UNIX System Laboratories, Inc. 5 * All or some portions of this file are derived from material licensed 6 * to the University of California by American Telephone and Telegraph 7 * Co. or Unix System Laboratories, Inc. and are reproduced herein with 8 * the permission of UNIX System Laboratories, Inc. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the University of 21 * California, Berkeley and its contributors. 22 * 4. Neither the name of the University nor the names of its contributors 23 * may be used to endorse or promote products derived from this software 24 * without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 29 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 36 * SUCH DAMAGE. 37 * 38 * @(#)subr_prf.c 8.3 (Berkeley) 1/21/94 39 * $Id: subr_prf.c,v 1.32 1996/03/23 21:23:43 jkh Exp $ 40 */ 41 42#include "opt_ddb.h" 43 44#include <sys/param.h> 45#include <sys/systm.h> 46#include <sys/reboot.h> 47#include <sys/msgbuf.h> 48#include <sys/proc.h> 49#include <sys/vnode.h> 50#include <sys/tty.h> 51#include <sys/tprintf.h> 52#include <sys/syslog.h> 53#include <sys/malloc.h> 54#include <sys/kernel.h> 55#include <sys/sysctl.h> 56#include <machine/cons.h> 57 58/* 59 * Note that stdarg.h and the ANSI style va_start macro is used for both 60 * ANSI and traditional C compilers. 61 */ 62#include <machine/stdarg.h> 63 64#if defined(DDB) || defined (KGDB) 65#ifdef DDB_UNATTENDED 66 static int debugger_on_panic = 0; 67#else 68 static int debugger_on_panic = 1; 69#endif 70 71SYSCTL_INT(_debug, OID_AUTO, debugger_on_panic, CTLFLAG_RW, 72 &debugger_on_panic, 0, ""); 73#endif 74 75#define TOCONS 0x01 76#define TOTTY 0x02 77#define TOLOG 0x04 78 79struct tty *constty; /* pointer to console "window" tty */ 80 81static void (*v_putc)(int) = cnputc; /* routine to putc on virtual console */ 82 83static void logpri __P((int level)); 84static void msglogchar(int c, void *dummyarg); 85struct putchar_arg {int flags; struct tty *tty; }; 86static void putchar __P((int ch, void *arg)); 87static char *ksprintn __P((u_long num, int base, int *len)); 88 89static int consintr = 1; /* Ok to handle console interrupts? */ 90 91/* 92 * Variable panicstr contains argument to first call to panic; used as flag 93 * to indicate that the kernel has already called panic. 94 */ 95const char *panicstr; 96 97/* 98 * Panic is called on unresolvable fatal errors. It prints "panic: mesg", 99 * and then reboots. If we are called twice, then we avoid trying to sync 100 * the disks as this often leads to recursive panics. 101 */ 102#ifdef __GNUC__ 103__dead /* panic() does not return */ 104#endif 105void 106panic(const char *fmt, ...) 107{ 108 int bootopt; 109 va_list ap; 110 111 bootopt = RB_AUTOBOOT | RB_DUMP; 112 if (panicstr) 113 bootopt |= RB_NOSYNC; 114 else 115 panicstr = fmt; 116 117 printf("panic: "); 118 va_start(ap, fmt); 119 vprintf(fmt, ap); 120 va_end(ap); 121 printf("\n"); 122 123#if defined(KGDB) || defined(DDB) 124 if (debugger_on_panic) { 125 kgdb_panic(); 126#ifdef DDB 127 Debugger ("panic"); 128#endif 129 } 130 boot(bootopt); 131#endif 132} 133 134 135/* 136 * Warn that a system table is full. 137 */ 138void 139tablefull(tab) 140 const char *tab; 141{ 142 143 log(LOG_ERR, "%s: table is full\n", tab); 144} 145 146/* 147 * Uprintf prints to the controlling terminal for the current process. 148 * It may block if the tty queue is overfull. No message is printed if 149 * the queue does not clear in a reasonable time. 150 */ 151void 152uprintf(const char *fmt, ...) 153{ 154 struct proc *p = curproc; 155 va_list ap; 156 struct putchar_arg pca; 157 158 if (p->p_flag & P_CONTROLT && p->p_session->s_ttyvp) { 159 va_start(ap, fmt); 160 pca.tty = p->p_session->s_ttyp; 161 pca.flags = TOTTY; 162 kvprintf(fmt, putchar, &pca, 10, ap); 163 va_end(ap); 164 } 165} 166 167tpr_t 168tprintf_open(p) 169 register struct proc *p; 170{ 171 172 if (p->p_flag & P_CONTROLT && p->p_session->s_ttyvp) { 173 SESSHOLD(p->p_session); 174 return ((tpr_t) p->p_session); 175 } 176 return ((tpr_t) NULL); 177} 178 179void 180tprintf_close(sess) 181 tpr_t sess; 182{ 183 184 if (sess) 185 SESSRELE((struct session *) sess); 186} 187 188/* 189 * tprintf prints on the controlling terminal associated 190 * with the given session. 191 */ 192void 193tprintf(tpr_t tpr, const char *fmt, ...) 194{ 195 register struct session *sess = (struct session *)tpr; 196 struct tty *tp = NULL; 197 int flags = TOLOG; 198 va_list ap; 199 struct putchar_arg pca; 200 201 logpri(LOG_INFO); 202 if (sess && sess->s_ttyvp && ttycheckoutq(sess->s_ttyp, 0)) { 203 flags |= TOTTY; 204 tp = sess->s_ttyp; 205 } 206 va_start(ap, fmt); 207 pca.tty = tp; 208 pca.flags = flags; 209 kvprintf(fmt, putchar, &pca, 10, ap); 210 va_end(ap); 211 logwakeup(); 212} 213 214/* 215 * Ttyprintf displays a message on a tty; it should be used only by 216 * the tty driver, or anything that knows the underlying tty will not 217 * be revoke(2)'d away. Other callers should use tprintf. 218 */ 219void 220ttyprintf(struct tty *tp, const char *fmt, ...) 221{ 222 va_list ap; 223 struct putchar_arg pca; 224 va_start(ap, fmt); 225 pca.tty = tp; 226 pca.flags = TOTTY; 227 kvprintf(fmt, putchar, &pca, 10, ap); 228 va_end(ap); 229} 230 231extern int log_open; 232 233/* 234 * Log writes to the log buffer, and guarantees not to sleep (so can be 235 * called by interrupt routines). If there is no process reading the 236 * log yet, it writes to the console also. 237 */ 238void 239log(int level, const char *fmt, ...) 240{ 241 register int s; 242 va_list ap; 243 244 s = splhigh(); 245 logpri(level); 246 va_start(ap, fmt); 247 248 kvprintf(fmt, msglogchar, NULL, 10, ap); 249 va_end(ap); 250 251 splx(s); 252 if (!log_open) { 253 struct putchar_arg pca; 254 va_start(ap, fmt); 255 pca.tty = NULL; 256 pca.flags = TOCONS; 257 kvprintf(fmt, putchar, &pca, 10, ap); 258 va_end(ap); 259 } 260 logwakeup(); 261} 262 263static void 264logpri(level) 265 int level; 266{ 267 register char *p; 268 269 msglogchar('<', NULL); 270 for (p = ksprintn((u_long)level, 10, NULL); *p;) 271 msglogchar(*p--, NULL); 272 msglogchar('>', NULL); 273} 274 275void 276addlog(const char *fmt, ...) 277{ 278 register int s; 279 va_list ap; 280 281 s = splhigh(); 282 va_start(ap, fmt); 283 kvprintf(fmt, msglogchar, NULL, 10, ap); 284 splx(s); 285 va_end(ap); 286 if (!log_open) { 287 struct putchar_arg pca; 288 va_start(ap, fmt); 289 pca.tty = NULL; 290 pca.flags = TOCONS; 291 kvprintf(fmt, putchar, &pca, 10, ap); 292 va_end(ap); 293 } 294 logwakeup(); 295} 296 297int 298printf(const char *fmt, ...) 299{ 300 va_list ap; 301 register int savintr; 302 struct putchar_arg pca; 303 int retval; 304 305 savintr = consintr; /* disable interrupts */ 306 consintr = 0; 307 va_start(ap, fmt); 308 pca.tty = NULL; 309 pca.flags = TOCONS | TOLOG; 310 retval = kvprintf(fmt, putchar, &pca, 10, ap); 311 va_end(ap); 312 if (!panicstr) 313 logwakeup(); 314 consintr = savintr; /* reenable interrupts */ 315 return retval; 316} 317 318void 319vprintf(const char *fmt, va_list ap) 320{ 321 register int savintr; 322 struct putchar_arg pca; 323 324 savintr = consintr; /* disable interrupts */ 325 consintr = 0; 326 pca.tty = NULL; 327 pca.flags = TOCONS | TOLOG; 328 kvprintf(fmt, putchar, &pca, 10, ap); 329 if (!panicstr) 330 logwakeup(); 331 consintr = savintr; /* reenable interrupts */ 332} 333 334/* 335 * Print a character on console or users terminal. If destination is 336 * the console then the last MSGBUFS characters are saved in msgbuf for 337 * inspection later. 338 */ 339static void 340putchar(int c, void *arg) 341{ 342 struct putchar_arg *ap = (struct putchar_arg*) arg; 343 int flags = ap->flags; 344 struct tty *tp = ap->tty; 345 if (panicstr) 346 constty = NULL; 347 if ((flags & TOCONS) && tp == NULL && constty) { 348 tp = constty; 349 flags |= TOTTY; 350 } 351 if ((flags & TOTTY) && tp && tputchar(c, tp) < 0 && 352 (flags & TOCONS) && tp == constty) 353 constty = NULL; 354 if ((flags & TOLOG)) 355 msglogchar(c, NULL); 356 if ((flags & TOCONS) && constty == NULL && c != '\0') 357 (*v_putc)(c); 358} 359 360/* 361 * Scaled down version of sprintf(3). 362 */ 363int 364sprintf(char *buf, const char *cfmt, ...) 365{ 366 int retval; 367 va_list ap; 368 369 va_start(ap, cfmt); 370 retval = kvprintf(cfmt, NULL, (void *)buf, 10, ap); 371 buf[retval] = '\0'; 372 va_end(ap); 373 return retval; 374} 375 376/* 377 * Put a number (base <= 16) in a buffer in reverse order; return an 378 * optional length and a pointer to the NULL terminated (preceded?) 379 * buffer. 380 */ 381static char * 382ksprintn(ul, base, lenp) 383 register u_long ul; 384 register int base, *lenp; 385{ /* A long in base 8, plus NULL. */ 386 static char buf[sizeof(long) * NBBY / 3 + 2]; 387 register char *p; 388 389 p = buf; 390 do { 391 *++p = hex2ascii(ul % base); 392 } while (ul /= base); 393 if (lenp) 394 *lenp = p - buf; 395 return (p); 396} 397 398/* 399 * Scaled down version of printf(3). 400 * 401 * Two additional formats: 402 * 403 * The format %b is supported to decode error registers. 404 * Its usage is: 405 * 406 * printf("reg=%b\n", regval, "<base><arg>*"); 407 * 408 * where <base> is the output base expressed as a control character, e.g. 409 * \10 gives octal; \20 gives hex. Each arg is a sequence of characters, 410 * the first of which gives the bit number to be inspected (origin 1), and 411 * the next characters (up to a control character, i.e. a character <= 32), 412 * give the name of the register. Thus: 413 * 414 * kprintf("reg=%b\n", 3, "\10\2BITTWO\1BITONE\n"); 415 * 416 * would produce output: 417 * 418 * reg=3<BITTWO,BITONE> 419 * 420 * XXX: %D -- Hexdump, takes pointer and separator string: 421 * ("%6D", ptr, ":") -> XX:XX:XX:XX:XX:XX 422 * ("%*D", len, ptr, " " -> XX XX XX XX ... 423 */ 424int 425kvprintf(char const *fmt, void (*func)(int, void*), void *arg, int radix, va_list ap) 426{ 427#define PCHAR(c) {int cc=(c); if (func) (*func)(cc,arg); else *d++ = cc; retval++; } 428 char *p, *q, *d; 429 u_char *up; 430 int ch, n; 431 u_long ul; 432 int base, lflag, tmp, width, ladjust, sharpflag, neg, sign, dot; 433 int dwidth; 434 char padc; 435 int retval = 0; 436 437 if (!func) 438 d = (char *) arg; 439 else 440 d = NULL; 441 442 if (fmt == NULL) 443 fmt = "(fmt null)\n"; 444 445 if (radix < 2 || radix > 36) 446 radix = 10; 447 448 for (;;) { 449 padc = ' '; 450 width = 0; 451 while ((ch = *(u_char *)fmt++) != '%') { 452 if (ch == '\0') 453 return retval; 454 PCHAR(ch); 455 } 456 lflag = 0; ladjust = 0; sharpflag = 0; neg = 0; 457 sign = 0; dot = 0; dwidth = 0; 458reswitch: switch (ch = *(u_char *)fmt++) { 459 case '.': 460 dot = 1; 461 goto reswitch; 462 case '#': 463 sharpflag = 1; 464 goto reswitch; 465 case '+': 466 sign = 1; 467 goto reswitch; 468 case '-': 469 ladjust = 1; 470 goto reswitch; 471 case '%': 472 PCHAR(ch); 473 break; 474 case '*': 475 if (!dot) { 476 width = va_arg(ap, int); 477 if (width < 0) { 478 ladjust = !ladjust; 479 width = -width; 480 } 481 } else { 482 dwidth = va_arg(ap, int); 483 } 484 goto reswitch; 485 case '0': 486 if (!dot) { 487 padc = '0'; 488 goto reswitch; 489 } 490 case '1': case '2': case '3': case '4': 491 case '5': case '6': case '7': case '8': case '9': 492 for (n = 0;; ++fmt) { 493 n = n * 10 + ch - '0'; 494 ch = *fmt; 495 if (ch < '0' || ch > '9') 496 break; 497 } 498 if (dot) 499 dwidth = n; 500 else 501 width = n; 502 goto reswitch; 503 case 'b': 504 ul = va_arg(ap, int); 505 p = va_arg(ap, char *); 506 for (q = ksprintn(ul, *p++, NULL); *q;) 507 PCHAR(*q--); 508 509 if (!ul) 510 break; 511 512 for (tmp = 0; *p;) { 513 n = *p++; 514 if (ul & (1 << (n - 1))) { 515 PCHAR(tmp ? ',' : '<'); 516 for (; (n = *p) > ' '; ++p) 517 PCHAR(n); 518 tmp = 1; 519 } else 520 for (; *p > ' '; ++p) 521 continue; 522 } 523 if (tmp) 524 PCHAR('>'); 525 break; 526 case 'c': 527 PCHAR(va_arg(ap, int)); 528 break; 529 case 'D': 530 up = va_arg(ap, u_char *); 531 p = va_arg(ap, char *); 532 if (!width) 533 width = 16; 534 while(width--) { 535 PCHAR(hex2ascii(*up >> 4)); 536 PCHAR(hex2ascii(*up & 0x0f)); 537 up++; 538 if (width) 539 for (q=p;*q;q++) 540 PCHAR(*q); 541 } 542 break; 543 case 'd': 544 ul = lflag ? va_arg(ap, long) : va_arg(ap, int); 545 sign = 1; 546 base = 10; 547 goto number; 548 case 'l': 549 lflag = 1; 550 goto reswitch; 551 case 'n': 552 ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int); 553 base = radix; 554 goto number; 555 case 'o': 556 ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int); 557 base = 8; 558 goto number; 559 case 'p': 560 ul = (u_long)va_arg(ap, void *); 561 base = 16; 562 PCHAR('0'); 563 PCHAR('x'); 564 goto number; 565 case 's': 566 p = va_arg(ap, char *); 567 if (p == NULL) 568 p = "(null)"; 569 if (!dot) 570 n = strlen (p); 571 else 572 for (n = 0; n < dwidth && p[n]; n++) 573 continue; 574 575 width -= n; 576 577 if (!ladjust && width > 0) 578 while (width--) 579 PCHAR(padc); 580 while (n--) 581 PCHAR(*p++); 582 if (ladjust && width > 0) 583 while (width--) 584 PCHAR(padc); 585 break; 586 case 'u': 587 ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int); 588 base = 10; 589 goto number; 590 case 'x': 591 ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int); 592 base = 16; 593number: if (sign && (long)ul < 0L) { 594 neg = 1; 595 ul = -(long)ul; 596 } 597 p = ksprintn(ul, base, &tmp); 598 if (sharpflag && ul != 0) { 599 if (base == 8) 600 tmp++; 601 else if (base == 16) 602 tmp += 2; 603 } 604 if (neg) 605 tmp++; 606 607 if (!ladjust && width && (width -= tmp) > 0) 608 while (width--) 609 PCHAR(padc); 610 if (neg) 611 PCHAR('-'); 612 if (sharpflag && ul != 0) { 613 if (base == 8) { 614 PCHAR('0'); 615 } else if (base == 16) { 616 PCHAR('0'); 617 PCHAR('x'); 618 } 619 } 620 621 while (*p) 622 PCHAR(*p--); 623 624 if (ladjust && width && (width -= tmp) > 0) 625 while (width--) 626 PCHAR(padc); 627 628 break; 629 default: 630 PCHAR('%'); 631 if (lflag) 632 PCHAR('l'); 633 PCHAR(ch); 634 break; 635 } 636 } 637#undef PCHAR 638} 639 640/* 641 * Put character in log buffer. 642 */ 643static void 644msglogchar(int c, void *dummyarg) 645{ 646 struct msgbuf *mbp; 647 648 if (c != '\0' && c != '\r' && c != 0177 && msgbufmapped) { 649 mbp = msgbufp; 650 if (mbp->msg_magic != MSG_MAGIC || 651 mbp->msg_bufx >= MSG_BSIZE || 652 mbp->msg_bufr >= MSG_BSIZE) { 653 bzero(mbp, sizeof(struct msgbuf)); 654 mbp->msg_magic = MSG_MAGIC; 655 } 656 mbp->msg_bufc[mbp->msg_bufx++] = c; 657 if (mbp->msg_bufx >= MSG_BSIZE) 658 mbp->msg_bufx = 0; 659 /* If the buffer is full, keep the most recent data. */ 660 if (mbp->msg_bufr == mbp->msg_bufx) { 661 if (++mbp->msg_bufr >= MSG_BSIZE) 662 mbp->msg_bufr = 0; 663 } 664 } 665} 666