hexdump.c revision 48728
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.55 1999/07/09 17:54:39 peter Exp $ 40 */ 41 42#include <sys/param.h> 43#include <sys/systm.h> 44#include <sys/kernel.h> 45#include <sys/msgbuf.h> 46#include <sys/malloc.h> 47#include <sys/proc.h> 48#include <sys/tty.h> 49#include <sys/tprintf.h> 50#include <sys/syslog.h> 51#include <machine/cons.h> 52 53/* 54 * Note that stdarg.h and the ANSI style va_start macro is used for both 55 * ANSI and traditional C compilers. 56 */ 57#include <machine/stdarg.h> 58 59#define TOCONS 0x01 60#define TOTTY 0x02 61#define TOLOG 0x04 62 63/* Max number conversion buffer length: a u_quad_t in base 2, plus NUL byte. */ 64#define MAXNBUF (sizeof(quad_t) * NBBY + 1) 65 66struct putchar_arg { 67 int flags; 68 struct tty *tty; 69}; 70 71struct snprintf_arg { 72 char *str; 73 size_t remain; 74}; 75 76struct tty *constty; /* pointer to console "window" tty */ 77 78static void (*v_putc)(int) = cnputc; /* routine to putc on virtual console */ 79static void logpri __P((int level)); 80static void msglogchar(int c, void *dummyarg); 81static void putchar __P((int ch, void *arg)); 82static char *ksprintn __P((char *nbuf, u_long num, int base, int *len)); 83static char *ksprintqn __P((char *nbuf, u_quad_t num, int base, int *len)); 84static void snprintf_func __P((int ch, void *arg)); 85 86static int consintr = 1; /* Ok to handle console interrupts? */ 87static int msgbufmapped; /* Set when safe to use msgbuf */ 88 89/* 90 * Warn that a system table is full. 91 */ 92void 93tablefull(tab) 94 const char *tab; 95{ 96 97 log(LOG_ERR, "%s: table is full\n", tab); 98} 99 100/* 101 * Uprintf prints to the controlling terminal for the current process. 102 * It may block if the tty queue is overfull. No message is printed if 103 * the queue does not clear in a reasonable time. 104 */ 105void 106uprintf(const char *fmt, ...) 107{ 108 struct proc *p = curproc; 109 va_list ap; 110 struct putchar_arg pca; 111 112 if (p->p_flag & P_CONTROLT && p->p_session->s_ttyvp) { 113 va_start(ap, fmt); 114 pca.tty = p->p_session->s_ttyp; 115 pca.flags = TOTTY; 116 kvprintf(fmt, putchar, &pca, 10, ap); 117 va_end(ap); 118 } 119} 120 121tpr_t 122tprintf_open(p) 123 register struct proc *p; 124{ 125 126 if (p->p_flag & P_CONTROLT && p->p_session->s_ttyvp) { 127 SESSHOLD(p->p_session); 128 return ((tpr_t) p->p_session); 129 } 130 return ((tpr_t) NULL); 131} 132 133void 134tprintf_close(sess) 135 tpr_t sess; 136{ 137 138 if (sess) 139 SESSRELE((struct session *) sess); 140} 141 142/* 143 * tprintf prints on the controlling terminal associated 144 * with the given session. 145 */ 146void 147tprintf(tpr_t tpr, const char *fmt, ...) 148{ 149 register struct session *sess = (struct session *)tpr; 150 struct tty *tp = NULL; 151 int flags = TOLOG; 152 va_list ap; 153 struct putchar_arg pca; 154 155 logpri(LOG_INFO); 156 if (sess && sess->s_ttyvp && ttycheckoutq(sess->s_ttyp, 0)) { 157 flags |= TOTTY; 158 tp = sess->s_ttyp; 159 } 160 va_start(ap, fmt); 161 pca.tty = tp; 162 pca.flags = flags; 163 kvprintf(fmt, putchar, &pca, 10, ap); 164 va_end(ap); 165 logwakeup(); 166} 167 168/* 169 * Ttyprintf displays a message on a tty; it should be used only by 170 * the tty driver, or anything that knows the underlying tty will not 171 * be revoke(2)'d away. Other callers should use tprintf. 172 */ 173void 174ttyprintf(struct tty *tp, const char *fmt, ...) 175{ 176 va_list ap; 177 struct putchar_arg pca; 178 va_start(ap, fmt); 179 pca.tty = tp; 180 pca.flags = TOTTY; 181 kvprintf(fmt, putchar, &pca, 10, ap); 182 va_end(ap); 183} 184 185extern int log_open; 186 187/* 188 * Log writes to the log buffer, and guarantees not to sleep (so can be 189 * called by interrupt routines). If there is no process reading the 190 * log yet, it writes to the console also. 191 */ 192void 193log(int level, const char *fmt, ...) 194{ 195 register int s; 196 va_list ap; 197 198 s = splhigh(); 199 logpri(level); 200 va_start(ap, fmt); 201 202 kvprintf(fmt, msglogchar, NULL, 10, ap); 203 va_end(ap); 204 205 splx(s); 206 if (!log_open) { 207 struct putchar_arg pca; 208 va_start(ap, fmt); 209 pca.tty = NULL; 210 pca.flags = TOCONS; 211 kvprintf(fmt, putchar, &pca, 10, ap); 212 va_end(ap); 213 } 214 logwakeup(); 215} 216 217static void 218logpri(level) 219 int level; 220{ 221 char nbuf[MAXNBUF]; 222 register char *p; 223 224 msglogchar('<', NULL); 225 for (p = ksprintn(nbuf, (u_long)level, 10, NULL); *p;) 226 msglogchar(*p--, NULL); 227 msglogchar('>', NULL); 228} 229 230int 231addlog(const char *fmt, ...) 232{ 233 register int s; 234 va_list ap; 235 int retval; 236 237 s = splhigh(); 238 va_start(ap, fmt); 239 retval = kvprintf(fmt, msglogchar, NULL, 10, ap); 240 splx(s); 241 va_end(ap); 242 if (!log_open) { 243 struct putchar_arg pca; 244 va_start(ap, fmt); 245 pca.tty = NULL; 246 pca.flags = TOCONS; 247 kvprintf(fmt, putchar, &pca, 10, ap); 248 va_end(ap); 249 } 250 logwakeup(); 251 return (retval); 252} 253 254int 255printf(const char *fmt, ...) 256{ 257 va_list ap; 258 register int savintr; 259 struct putchar_arg pca; 260 int retval; 261 262 savintr = consintr; /* disable interrupts */ 263 consintr = 0; 264 va_start(ap, fmt); 265 pca.tty = NULL; 266 pca.flags = TOCONS | TOLOG; 267 retval = kvprintf(fmt, putchar, &pca, 10, ap); 268 va_end(ap); 269 if (!panicstr) 270 logwakeup(); 271 consintr = savintr; /* reenable interrupts */ 272 return retval; 273} 274 275void 276vprintf(const char *fmt, va_list ap) 277{ 278 register int savintr; 279 struct putchar_arg pca; 280 281 savintr = consintr; /* disable interrupts */ 282 consintr = 0; 283 pca.tty = NULL; 284 pca.flags = TOCONS | TOLOG; 285 kvprintf(fmt, putchar, &pca, 10, ap); 286 if (!panicstr) 287 logwakeup(); 288 consintr = savintr; /* reenable interrupts */ 289} 290 291/* 292 * Print a character on console or users terminal. If destination is 293 * the console then the last bunch of characters are saved in msgbuf for 294 * inspection later. 295 */ 296static void 297putchar(int c, void *arg) 298{ 299 struct putchar_arg *ap = (struct putchar_arg*) arg; 300 int flags = ap->flags; 301 struct tty *tp = ap->tty; 302 if (panicstr) 303 constty = NULL; 304 if ((flags & TOCONS) && tp == NULL && constty) { 305 tp = constty; 306 flags |= TOTTY; 307 } 308 if ((flags & TOTTY) && tp && tputchar(c, tp) < 0 && 309 (flags & TOCONS) && tp == constty) 310 constty = NULL; 311 if ((flags & TOLOG)) 312 msglogchar(c, NULL); 313 if ((flags & TOCONS) && constty == NULL && c != '\0') 314 (*v_putc)(c); 315} 316 317/* 318 * Scaled down version of sprintf(3). 319 */ 320int 321sprintf(char *buf, const char *cfmt, ...) 322{ 323 int retval; 324 va_list ap; 325 326 va_start(ap, cfmt); 327 retval = kvprintf(cfmt, NULL, (void *)buf, 10, ap); 328 buf[retval] = '\0'; 329 va_end(ap); 330 return retval; 331} 332 333/* 334 * Scaled down version of vsprintf(3). 335 */ 336int 337vsprintf(char *buf, const char *cfmt, va_list ap) 338{ 339 int retval; 340 341 retval = kvprintf(cfmt, NULL, (void *)buf, 10, ap); 342 buf[retval] = '\0'; 343 return retval; 344} 345 346/* 347 * Scaled down version of snprintf(3). 348 */ 349int 350snprintf(char *str, size_t size, const char *format, ...) 351{ 352 int retval; 353 va_list ap; 354 355 va_start(ap, format); 356 retval = vsnprintf(str, size, format, ap); 357 va_end(ap); 358 return(retval); 359} 360 361/* 362 * Scaled down version of vsnprintf(3). 363 */ 364int 365vsnprintf(char *str, size_t size, const char *format, va_list ap) 366{ 367 struct snprintf_arg info; 368 int retval; 369 370 info.str = str; 371 info.remain = size; 372 retval = kvprintf(format, snprintf_func, &info, 10, ap); 373 if (info.remain >= 1) 374 *info.str++ = '\0'; 375 return retval; 376} 377 378static void 379snprintf_func(int ch, void *arg) 380{ 381 struct snprintf_arg *const info = arg; 382 383 if (info->remain >= 2) { 384 *info->str++ = ch; 385 info->remain--; 386 } 387} 388 389/* 390 * Put a NUL-terminated ASCII number (base <= 36) in a buffer in reverse 391 * order; return an optional length and a pointer to the last character 392 * written in the buffer (i.e., the first character of the string). 393 * The buffer pointed to by `nbuf' must have length >= MAXNBUF. 394 */ 395static char * 396ksprintn(nbuf, ul, base, lenp) 397 char *nbuf; 398 register u_long ul; 399 register int base, *lenp; 400{ 401 register char *p; 402 403 p = nbuf; 404 *p = '\0'; 405 do { 406 *++p = hex2ascii(ul % base); 407 } while (ul /= base); 408 if (lenp) 409 *lenp = p - nbuf; 410 return (p); 411} 412/* ksprintn, but for a quad_t. */ 413static char * 414ksprintqn(nbuf, uq, base, lenp) 415 char *nbuf; 416 register u_quad_t uq; 417 register int base, *lenp; 418{ 419 register char *p; 420 421 p = nbuf; 422 *p = '\0'; 423 do { 424 *++p = hex2ascii(uq % base); 425 } while (uq /= base); 426 if (lenp) 427 *lenp = p - nbuf; 428 return (p); 429} 430 431/* 432 * Scaled down version of printf(3). 433 * 434 * Two additional formats: 435 * 436 * The format %b is supported to decode error registers. 437 * Its usage is: 438 * 439 * printf("reg=%b\n", regval, "<base><arg>*"); 440 * 441 * where <base> is the output base expressed as a control character, e.g. 442 * \10 gives octal; \20 gives hex. Each arg is a sequence of characters, 443 * the first of which gives the bit number to be inspected (origin 1), and 444 * the next characters (up to a control character, i.e. a character <= 32), 445 * give the name of the register. Thus: 446 * 447 * kvprintf("reg=%b\n", 3, "\10\2BITTWO\1BITONE\n"); 448 * 449 * would produce output: 450 * 451 * reg=3<BITTWO,BITONE> 452 * 453 * XXX: %D -- Hexdump, takes pointer and separator string: 454 * ("%6D", ptr, ":") -> XX:XX:XX:XX:XX:XX 455 * ("%*D", len, ptr, " " -> XX XX XX XX ... 456 */ 457int 458kvprintf(char const *fmt, void (*func)(int, void*), void *arg, int radix, va_list ap) 459{ 460#define PCHAR(c) {int cc=(c); if (func) (*func)(cc,arg); else *d++ = cc; retval++; } 461 char nbuf[MAXNBUF]; 462 char *p, *q, *d; 463 u_char *up; 464 int ch, n; 465 u_long ul; 466 u_quad_t uq; 467 int base, lflag, qflag, tmp, width, ladjust, sharpflag, neg, sign, dot; 468 int dwidth; 469 char padc; 470 int retval = 0; 471 472 ul = 0; 473 uq = 0; 474 if (!func) 475 d = (char *) arg; 476 else 477 d = NULL; 478 479 if (fmt == NULL) 480 fmt = "(fmt null)\n"; 481 482 if (radix < 2 || radix > 36) 483 radix = 10; 484 485 for (;;) { 486 padc = ' '; 487 width = 0; 488 while ((ch = (u_char)*fmt++) != '%') { 489 if (ch == '\0') 490 return retval; 491 PCHAR(ch); 492 } 493 qflag = 0; lflag = 0; ladjust = 0; sharpflag = 0; neg = 0; 494 sign = 0; dot = 0; dwidth = 0; 495reswitch: switch (ch = (u_char)*fmt++) { 496 case '.': 497 dot = 1; 498 goto reswitch; 499 case '#': 500 sharpflag = 1; 501 goto reswitch; 502 case '+': 503 sign = 1; 504 goto reswitch; 505 case '-': 506 ladjust = 1; 507 goto reswitch; 508 case '%': 509 PCHAR(ch); 510 break; 511 case '*': 512 if (!dot) { 513 width = va_arg(ap, int); 514 if (width < 0) { 515 ladjust = !ladjust; 516 width = -width; 517 } 518 } else { 519 dwidth = va_arg(ap, int); 520 } 521 goto reswitch; 522 case '0': 523 if (!dot) { 524 padc = '0'; 525 goto reswitch; 526 } 527 case '1': case '2': case '3': case '4': 528 case '5': case '6': case '7': case '8': case '9': 529 for (n = 0;; ++fmt) { 530 n = n * 10 + ch - '0'; 531 ch = *fmt; 532 if (ch < '0' || ch > '9') 533 break; 534 } 535 if (dot) 536 dwidth = n; 537 else 538 width = n; 539 goto reswitch; 540 case 'b': 541 ul = va_arg(ap, int); 542 p = va_arg(ap, char *); 543 for (q = ksprintn(nbuf, ul, *p++, NULL); *q;) 544 PCHAR(*q--); 545 546 if (!ul) 547 break; 548 549 for (tmp = 0; *p;) { 550 n = *p++; 551 if (ul & (1 << (n - 1))) { 552 PCHAR(tmp ? ',' : '<'); 553 for (; (n = *p) > ' '; ++p) 554 PCHAR(n); 555 tmp = 1; 556 } else 557 for (; *p > ' '; ++p) 558 continue; 559 } 560 if (tmp) 561 PCHAR('>'); 562 break; 563 case 'c': 564 PCHAR(va_arg(ap, int)); 565 break; 566 case 'D': 567 up = va_arg(ap, u_char *); 568 p = va_arg(ap, char *); 569 if (!width) 570 width = 16; 571 while(width--) { 572 PCHAR(hex2ascii(*up >> 4)); 573 PCHAR(hex2ascii(*up & 0x0f)); 574 up++; 575 if (width) 576 for (q=p;*q;q++) 577 PCHAR(*q); 578 } 579 break; 580 case 'd': 581 if (qflag) 582 uq = va_arg(ap, quad_t); 583 else if (lflag) 584 ul = va_arg(ap, long); 585 else 586 ul = va_arg(ap, int); 587 sign = 1; 588 base = 10; 589 goto number; 590 case 'l': 591 lflag = 1; 592 goto reswitch; 593 case 'o': 594 if (qflag) 595 uq = va_arg(ap, u_quad_t); 596 else if (lflag) 597 ul = va_arg(ap, u_long); 598 else 599 ul = va_arg(ap, u_int); 600 base = 8; 601 goto nosign; 602 case 'p': 603 ul = (uintptr_t)va_arg(ap, void *); 604 base = 16; 605 sharpflag = (width == 0); 606 goto nosign; 607 case 'q': 608 qflag = 1; 609 goto reswitch; 610 case 'n': 611 case 'r': 612 if (qflag) 613 uq = va_arg(ap, u_quad_t); 614 else if (lflag) 615 ul = va_arg(ap, u_long); 616 else 617 ul = sign ? 618 (u_long)va_arg(ap, int) : va_arg(ap, u_int); 619 base = radix; 620 goto number; 621 case 's': 622 p = va_arg(ap, char *); 623 if (p == NULL) 624 p = "(null)"; 625 if (!dot) 626 n = strlen (p); 627 else 628 for (n = 0; n < dwidth && p[n]; n++) 629 continue; 630 631 width -= n; 632 633 if (!ladjust && width > 0) 634 while (width--) 635 PCHAR(padc); 636 while (n--) 637 PCHAR(*p++); 638 if (ladjust && width > 0) 639 while (width--) 640 PCHAR(padc); 641 break; 642 case 'u': 643 if (qflag) 644 uq = va_arg(ap, u_quad_t); 645 else if (lflag) 646 ul = va_arg(ap, u_long); 647 else 648 ul = va_arg(ap, u_int); 649 base = 10; 650 goto nosign; 651 case 'x': 652 if (qflag) 653 uq = va_arg(ap, u_quad_t); 654 else if (lflag) 655 ul = va_arg(ap, u_long); 656 else 657 ul = va_arg(ap, u_int); 658 base = 16; 659 goto nosign; 660 case 'z': 661 if (qflag) 662 uq = va_arg(ap, u_quad_t); 663 else if (lflag) 664 ul = va_arg(ap, u_long); 665 else 666 ul = sign ? 667 (u_long)va_arg(ap, int) : va_arg(ap, u_int); 668 base = 16; 669 goto number; 670nosign: sign = 0; 671number: 672 if (qflag) { 673 if (sign && (quad_t)uq < 0) { 674 neg = 1; 675 uq = -(quad_t)uq; 676 } 677 p = ksprintqn(nbuf, uq, base, &tmp); 678 } else { 679 if (sign && (long)ul < 0) { 680 neg = 1; 681 ul = -(long)ul; 682 } 683 p = ksprintn(nbuf, ul, base, &tmp); 684 } 685 if (sharpflag && (qflag ? uq != 0 : ul != 0)) { 686 if (base == 8) 687 tmp++; 688 else if (base == 16) 689 tmp += 2; 690 } 691 if (neg) 692 tmp++; 693 694 if (!ladjust && width && (width -= tmp) > 0) 695 while (width--) 696 PCHAR(padc); 697 if (neg) 698 PCHAR('-'); 699 if (sharpflag && qflag ? (uq != 0) : (ul != 0)) { 700 if (base == 8) { 701 PCHAR('0'); 702 } else if (base == 16) { 703 PCHAR('0'); 704 PCHAR('x'); 705 } 706 } 707 708 while (*p) 709 PCHAR(*p--); 710 711 if (ladjust && width && (width -= tmp) > 0) 712 while (width--) 713 PCHAR(padc); 714 715 break; 716 default: 717 PCHAR('%'); 718 if (lflag) 719 PCHAR('l'); 720 PCHAR(ch); 721 break; 722 } 723 } 724#undef PCHAR 725} 726 727/* 728 * Put character in log buffer. 729 */ 730static void 731msglogchar(int c, void *dummyarg) 732{ 733 struct msgbuf *mbp; 734 735 if (c != '\0' && c != '\r' && c != 0177 && msgbufmapped) { 736 mbp = msgbufp; 737 mbp->msg_ptr[mbp->msg_bufx++] = c; 738 if (mbp->msg_bufx >= mbp->msg_size) 739 mbp->msg_bufx = 0; 740 /* If the buffer is full, keep the most recent data. */ 741 if (mbp->msg_bufr == mbp->msg_bufx) { 742 if (++mbp->msg_bufr >= mbp->msg_size) 743 mbp->msg_bufr = 0; 744 } 745 } 746} 747 748static void 749msgbufcopy(struct msgbuf *oldp) 750{ 751 int pos; 752 753 pos = oldp->msg_bufr; 754 while (pos != oldp->msg_bufx) { 755 msglogchar(oldp->msg_ptr[pos], NULL); 756 if (++pos >= oldp->msg_size) 757 pos = 0; 758 } 759} 760 761void 762msgbufinit(void *ptr, size_t size) 763{ 764 char *cp; 765 static struct msgbuf *oldp = NULL; 766 767 cp = (char *)ptr; 768 msgbufp = (struct msgbuf *) (cp + size - sizeof(*msgbufp)); 769 if (msgbufp->msg_magic != MSG_MAGIC || msgbufp->msg_ptr != cp) { 770 bzero(cp, size); 771 msgbufp->msg_magic = MSG_MAGIC; 772 msgbufp->msg_size = (char *)msgbufp - cp; 773 msgbufp->msg_ptr = cp; 774 } 775 if (msgbufmapped && oldp != msgbufp) 776 msgbufcopy(oldp); 777 msgbufmapped = 1; 778 oldp = msgbufp; 779} 780 781#include "opt_ddb.h" 782#ifdef DDB 783#include <ddb/ddb.h> 784 785DB_SHOW_COMMAND(msgbuf, db_show_msgbuf) 786{ 787 int i, j; 788 789 if (!msgbufmapped) { 790 db_printf("msgbuf not mapped yet\n"); 791 return; 792 } 793 db_printf("msgbufp = %p\n", msgbufp); 794 db_printf("magic = %x, size = %d, r= %d, w = %d, ptr = %p\n", 795 msgbufp->msg_magic, msgbufp->msg_size, msgbufp->msg_bufr, 796 msgbufp->msg_bufx, msgbufp->msg_ptr); 797 for (i = 0; i < msgbufp->msg_size; i++) { 798 j = (i + msgbufp->msg_bufr) % msgbufp->msg_size; 799 db_printf("%c", msgbufp->msg_ptr[j]); 800 } 801 db_printf("\n"); 802} 803 804#endif /* DDB */ 805