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