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