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