hexdump.c revision 1542
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 */ 40 41#include <sys/param.h> 42#include <sys/systm.h> 43#include <sys/buf.h> 44#include <sys/conf.h> 45#include <sys/reboot.h> 46#include <sys/msgbuf.h> 47#include <sys/proc.h> 48#include <sys/ioctl.h> 49#include <sys/vnode.h> 50#include <sys/file.h> 51#include <sys/tty.h> 52#include <sys/tprintf.h> 53#include <sys/syslog.h> 54#include <sys/malloc.h> 55 56/* 57 * Note that stdarg.h and the ANSI style va_start macro is used for both 58 * ANSI and traditional C compilers. 59 */ 60#include <machine/stdarg.h> 61 62#ifdef KADB 63#include <machine/kdbparam.h> 64#endif 65 66#define TOCONS 0x01 67#define TOTTY 0x02 68#define TOLOG 0x04 69 70struct tty *constty; /* pointer to console "window" tty */ 71 72extern cnputc(); /* standard console putc */ 73int (*v_putc)() = cnputc; /* routine to putc on virtual console */ 74 75void logpri __P((int level)); 76static void putchar __P((int ch, int flags, struct tty *tp)); 77static char *ksprintn __P((u_long num, int base, int *len)); 78void kprintf __P((const char *fmt, int flags, struct tty *tp, va_list ap)); 79 80int consintr = 1; /* Ok to handle console interrupts? */ 81 82/* 83 * Variable panicstr contains argument to first call to panic; used as flag 84 * to indicate that the kernel has already called panic. 85 */ 86const char *panicstr; 87 88/* 89 * Panic is called on unresolvable fatal errors. It prints "panic: mesg", 90 * and then reboots. If we are called twice, then we avoid trying to sync 91 * the disks as this often leads to recursive panics. 92 */ 93#ifdef __GNUC__ 94volatile void boot(int flags); /* boot() does not return */ 95volatile /* panic() does not return */ 96#endif 97void 98#ifdef __STDC__ 99panic(const char *fmt, ...) 100#else 101panic(fmt, va_alist) 102 char *fmt; 103#endif 104{ 105 int bootopt; 106 va_list ap; 107 108 bootopt = RB_AUTOBOOT | RB_DUMP; 109 if (panicstr) 110 bootopt |= RB_NOSYNC; 111 else 112 panicstr = fmt; 113 114 va_start(ap, fmt); 115 printf("panic: %r\n", fmt, ap); 116 va_end(ap); 117 118#ifdef KGDB 119 kgdb_panic(); 120#endif 121#ifdef KADB 122 if (boothowto & RB_KDB) 123 kdbpanic(); 124#endif 125 boot(bootopt); 126} 127 128/* 129 * Warn that a system table is full. 130 */ 131void 132tablefull(tab) 133 const char *tab; 134{ 135 136 log(LOG_ERR, "%s: table is full\n", tab); 137} 138 139/* 140 * Uprintf prints to the controlling terminal for the current process. 141 * It may block if the tty queue is overfull. No message is printed if 142 * the queue does not clear in a reasonable time. 143 */ 144void 145#ifdef __STDC__ 146uprintf(const char *fmt, ...) 147#else 148uprintf(fmt, va_alist) 149 char *fmt; 150#endif 151{ 152 register struct proc *p = curproc; 153 va_list ap; 154 155 if (p->p_flag & P_CONTROLT && p->p_session->s_ttyvp) { 156 va_start(ap, fmt); 157 kprintf(fmt, TOTTY, p->p_session->s_ttyp, ap); 158 va_end(ap); 159 } 160} 161 162tpr_t 163tprintf_open(p) 164 register struct proc *p; 165{ 166 167 if (p->p_flag & P_CONTROLT && p->p_session->s_ttyvp) { 168 SESSHOLD(p->p_session); 169 return ((tpr_t) p->p_session); 170 } 171 return ((tpr_t) NULL); 172} 173 174void 175tprintf_close(sess) 176 tpr_t sess; 177{ 178 179 if (sess) 180 SESSRELE((struct session *) sess); 181} 182 183/* 184 * tprintf prints on the controlling terminal associated 185 * with the given session. 186 */ 187void 188#ifdef __STDC__ 189tprintf(tpr_t tpr, const char *fmt, ...) 190#else 191tprintf(tpr, fmt, va_alist) 192 tpr_t tpr; 193 char *fmt; 194#endif 195{ 196 register struct session *sess = (struct session *)tpr; 197 struct tty *tp = NULL; 198 int flags = TOLOG; 199 va_list ap; 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 kprintf(fmt, flags, tp, ap); 208 va_end(ap); 209 logwakeup(); 210} 211 212/* 213 * Ttyprintf displays a message on a tty; it should be used only by 214 * the tty driver, or anything that knows the underlying tty will not 215 * be revoke(2)'d away. Other callers should use tprintf. 216 */ 217void 218#ifdef __STDC__ 219ttyprintf(struct tty *tp, const char *fmt, ...) 220#else 221ttyprintf(tp, fmt, va_alist) 222 struct tty *tp; 223 char *fmt; 224#endif 225{ 226 va_list ap; 227 228 va_start(ap, fmt); 229 kprintf(fmt, TOTTY, tp, ap); 230 va_end(ap); 231} 232 233extern int log_open; 234 235/* 236 * Log writes to the log buffer, and guarantees not to sleep (so can be 237 * called by interrupt routines). If there is no process reading the 238 * log yet, it writes to the console also. 239 */ 240void 241#ifdef __STDC__ 242log(int level, const char *fmt, ...) 243#else 244log(level, fmt, va_alist) 245 int level; 246 char *fmt; 247#endif 248{ 249 register int s; 250 va_list ap; 251 252 s = splhigh(); 253 logpri(level); 254 va_start(ap, fmt); 255 kprintf(fmt, TOLOG, NULL, ap); 256 splx(s); 257 va_end(ap); 258 if (!log_open) { 259 va_start(ap, fmt); 260 kprintf(fmt, TOCONS, NULL, ap); 261 va_end(ap); 262 } 263 logwakeup(); 264} 265 266void 267logpri(level) 268 int level; 269{ 270 register int ch; 271 register char *p; 272 273 putchar('<', TOLOG, NULL); 274 for (p = ksprintn((u_long)level, 10, NULL); ch = *p--;) 275 putchar(ch, TOLOG, NULL); 276 putchar('>', TOLOG, NULL); 277} 278 279void 280#ifdef __STDC__ 281addlog(const char *fmt, ...) 282#else 283addlog(fmt, va_alist) 284 char *fmt; 285#endif 286{ 287 register int s; 288 va_list ap; 289 290 s = splhigh(); 291 va_start(ap, fmt); 292 kprintf(fmt, TOLOG, NULL, ap); 293 splx(s); 294 va_end(ap); 295 if (!log_open) { 296 va_start(ap, fmt); 297 kprintf(fmt, TOCONS, NULL, ap); 298 va_end(ap); 299 } 300 logwakeup(); 301} 302 303void 304#ifdef __STDC__ 305printf(const char *fmt, ...) 306#else 307printf(fmt, va_alist) 308 char *fmt; 309#endif 310{ 311 va_list ap; 312 register int savintr; 313 314 savintr = consintr; /* disable interrupts */ 315 consintr = 0; 316 va_start(ap, fmt); 317 kprintf(fmt, TOCONS | TOLOG, NULL, ap); 318 va_end(ap); 319 if (!panicstr) 320 logwakeup(); 321 consintr = savintr; /* reenable interrupts */ 322} 323 324/* 325 * Scaled down version of printf(3). 326 * 327 * Two additional formats: 328 * 329 * The format %b is supported to decode error registers. 330 * Its usage is: 331 * 332 * printf("reg=%b\n", regval, "<base><arg>*"); 333 * 334 * where <base> is the output base expressed as a control character, e.g. 335 * \10 gives octal; \20 gives hex. Each arg is a sequence of characters, 336 * the first of which gives the bit number to be inspected (origin 1), and 337 * the next characters (up to a control character, i.e. a character <= 32), 338 * give the name of the register. Thus: 339 * 340 * kprintf("reg=%b\n", 3, "\10\2BITTWO\1BITONE\n"); 341 * 342 * would produce output: 343 * 344 * reg=3<BITTWO,BITONE> 345 * 346 * The format %r passes an additional format string and argument list 347 * recursively. Its usage is: 348 * 349 * fn(char *fmt, ...) 350 * { 351 * va_list ap; 352 * va_start(ap, fmt); 353 * printf("prefix: %r: suffix\n", fmt, ap); 354 * va_end(ap); 355 * } 356 * 357 * Space or zero padding and a field width are supported for the numeric 358 * formats only. 359 */ 360void 361kprintf(fmt, flags, tp, ap) 362 register const char *fmt; 363 int flags; 364 struct tty *tp; 365 va_list ap; 366{ 367 register char *p, *q; 368 register int ch, n; 369 u_long ul; 370 int base, lflag, tmp, width; 371 char padc; 372 373 for (;;) { 374 padc = ' '; 375 width = 0; 376 while ((ch = *(u_char *)fmt++) != '%') { 377 if (ch == '\0') 378 return; 379 putchar(ch, flags, tp); 380 } 381 lflag = 0; 382reswitch: switch (ch = *(u_char *)fmt++) { 383 case '0': 384 padc = '0'; 385 goto reswitch; 386 case '1': case '2': case '3': case '4': 387 case '5': case '6': case '7': case '8': case '9': 388 for (width = 0;; ++fmt) { 389 width = width * 10 + ch - '0'; 390 ch = *fmt; 391 if (ch < '0' || ch > '9') 392 break; 393 } 394 goto reswitch; 395 case 'l': 396 lflag = 1; 397 goto reswitch; 398 case 'b': 399 ul = va_arg(ap, int); 400 p = va_arg(ap, char *); 401 for (q = ksprintn(ul, *p++, NULL); ch = *q--;) 402 putchar(ch, flags, tp); 403 404 if (!ul) 405 break; 406 407 for (tmp = 0; n = *p++;) { 408 if (ul & (1 << (n - 1))) { 409 putchar(tmp ? ',' : '<', flags, tp); 410 for (; (n = *p) > ' '; ++p) 411 putchar(n, flags, tp); 412 tmp = 1; 413 } else 414 for (; *p > ' '; ++p) 415 continue; 416 } 417 if (tmp) 418 putchar('>', flags, tp); 419 break; 420 case 'c': 421 putchar(va_arg(ap, int), flags, tp); 422 break; 423 case 'r': 424 p = va_arg(ap, char *); 425 kprintf(p, flags, tp, va_arg(ap, va_list)); 426 break; 427 case 's': 428 p = va_arg(ap, char *); 429 while (ch = *p++) 430 putchar(ch, flags, tp); 431 break; 432 case 'd': 433 ul = lflag ? va_arg(ap, long) : va_arg(ap, int); 434 if ((long)ul < 0) { 435 putchar('-', flags, tp); 436 ul = -(long)ul; 437 } 438 base = 10; 439 goto number; 440 case 'o': 441 ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int); 442 base = 8; 443 goto number; 444 case 'u': 445 ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int); 446 base = 10; 447 goto number; 448 case 'x': 449 ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int); 450 base = 16; 451number: p = ksprintn(ul, base, &tmp); 452 if (width && (width -= tmp) > 0) 453 while (width--) 454 putchar(padc, flags, tp); 455 while (ch = *p--) 456 putchar(ch, flags, tp); 457 break; 458 default: 459 putchar('%', flags, tp); 460 if (lflag) 461 putchar('l', flags, tp); 462 /* FALLTHROUGH */ 463 case '%': 464 putchar(ch, flags, tp); 465 } 466 } 467} 468 469/* 470 * Print a character on console or users terminal. If destination is 471 * the console then the last MSGBUFS characters are saved in msgbuf for 472 * inspection later. 473 */ 474static void 475putchar(c, flags, tp) 476 register int c; 477 int flags; 478 struct tty *tp; 479{ 480 extern int msgbufmapped; 481 register struct msgbuf *mbp; 482 483 if (panicstr) 484 constty = NULL; 485 if ((flags & TOCONS) && tp == NULL && constty) { 486 tp = constty; 487 flags |= TOTTY; 488 } 489 if ((flags & TOTTY) && tp && tputchar(c, tp) < 0 && 490 (flags & TOCONS) && tp == constty) 491 constty = NULL; 492 if ((flags & TOLOG) && 493 c != '\0' && c != '\r' && c != 0177 && msgbufmapped) { 494 mbp = msgbufp; 495 if (mbp->msg_magic != MSG_MAGIC) { 496 bzero((caddr_t)mbp, sizeof(*mbp)); 497 mbp->msg_magic = MSG_MAGIC; 498 } 499 mbp->msg_bufc[mbp->msg_bufx++] = c; 500 if (mbp->msg_bufx < 0 || mbp->msg_bufx >= MSG_BSIZE) 501 mbp->msg_bufx = 0; 502 } 503 if ((flags & TOCONS) && constty == NULL && c != '\0') 504 (*v_putc)(c); 505} 506 507/* 508 * Scaled down version of sprintf(3). 509 */ 510#ifdef __STDC__ 511sprintf(char *buf, const char *cfmt, ...) 512#else 513sprintf(buf, cfmt, va_alist) 514 char *buf, *cfmt; 515#endif 516{ 517 register const char *fmt = cfmt; 518 register char *p, *bp; 519 register int ch, base; 520 u_long ul; 521 int lflag; 522 va_list ap; 523 524 va_start(ap, cfmt); 525 for (bp = buf; ; ) { 526 while ((ch = *(u_char *)fmt++) != '%') 527 if ((*bp++ = ch) == '\0') 528 return ((bp - buf) - 1); 529 530 lflag = 0; 531reswitch: switch (ch = *(u_char *)fmt++) { 532 case 'l': 533 lflag = 1; 534 goto reswitch; 535 case 'c': 536 *bp++ = va_arg(ap, int); 537 break; 538 case 's': 539 p = va_arg(ap, char *); 540 while (*bp++ = *p++) 541 continue; 542 --bp; 543 break; 544 case 'd': 545 ul = lflag ? va_arg(ap, long) : va_arg(ap, int); 546 if ((long)ul < 0) { 547 *bp++ = '-'; 548 ul = -(long)ul; 549 } 550 base = 10; 551 goto number; 552 break; 553 case 'o': 554 ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int); 555 base = 8; 556 goto number; 557 break; 558 case 'u': 559 ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int); 560 base = 10; 561 goto number; 562 break; 563 case 'x': 564 ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int); 565 base = 16; 566number: for (p = ksprintn(ul, base, NULL); ch = *p--;) 567 *bp++ = ch; 568 break; 569 default: 570 *bp++ = '%'; 571 if (lflag) 572 *bp++ = 'l'; 573 /* FALLTHROUGH */ 574 case '%': 575 *bp++ = ch; 576 } 577 } 578 va_end(ap); 579} 580 581/* 582 * Put a number (base <= 16) in a buffer in reverse order; return an 583 * optional length and a pointer to the NULL terminated (preceded?) 584 * buffer. 585 */ 586static char * 587ksprintn(ul, base, lenp) 588 register u_long ul; 589 register int base, *lenp; 590{ /* A long in base 8, plus NULL. */ 591 static char buf[sizeof(long) * NBBY / 3 + 2]; 592 register char *p; 593 594 p = buf; 595 do { 596 *++p = "0123456789abcdef"[ul % base]; 597 } while (ul /= base); 598 if (lenp) 599 *lenp = p - buf; 600 return (p); 601} 602