hexdump.c revision 37505
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.46 1998/05/28 09:30:20 phk 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 * Put a number (base <= 16) in a buffer in reverse order; return an
320 * optional length and a pointer to the NULL terminated (preceded?)
321 * buffer.
322 */
323static char *
324ksprintn(ul, base, lenp)
325	register u_long ul;
326	register int base, *lenp;
327{					/* A long in base 8, plus NULL. */
328	static char buf[sizeof(long) * NBBY / 3 + 2];
329	register char *p;
330
331	p = buf;
332	do {
333		*++p = hex2ascii(ul % base);
334	} while (ul /= base);
335	if (lenp)
336		*lenp = p - buf;
337	return (p);
338}
339
340/*
341 * Scaled down version of printf(3).
342 *
343 * Two additional formats:
344 *
345 * The format %b is supported to decode error registers.
346 * Its usage is:
347 *
348 *	printf("reg=%b\n", regval, "<base><arg>*");
349 *
350 * where <base> is the output base expressed as a control character, e.g.
351 * \10 gives octal; \20 gives hex.  Each arg is a sequence of characters,
352 * the first of which gives the bit number to be inspected (origin 1), and
353 * the next characters (up to a control character, i.e. a character <= 32),
354 * give the name of the register.  Thus:
355 *
356 *	kvprintf("reg=%b\n", 3, "\10\2BITTWO\1BITONE\n");
357 *
358 * would produce output:
359 *
360 *	reg=3<BITTWO,BITONE>
361 *
362 * XXX:  %D  -- Hexdump, takes pointer and separator string:
363 *		("%6D", ptr, ":")   -> XX:XX:XX:XX:XX:XX
364 *		("%*D", len, ptr, " " -> XX XX XX XX ...
365 */
366int
367kvprintf(char const *fmt, void (*func)(int, void*), void *arg, int radix, va_list ap)
368{
369#define PCHAR(c) {int cc=(c); if (func) (*func)(cc,arg); else *d++ = cc; retval++; }
370	char *p, *q, *d;
371	u_char *up;
372	int ch, n;
373	u_long ul;
374	int base, lflag, tmp, width, ladjust, sharpflag, neg, sign, dot;
375	int dwidth;
376	char padc;
377	int retval = 0;
378
379	if (!func)
380		d = (char *) arg;
381	else
382		d = NULL;
383
384	if (fmt == NULL)
385		fmt = "(fmt null)\n";
386
387	if (radix < 2 || radix > 36)
388		radix = 10;
389
390	for (;;) {
391		padc = ' ';
392		width = 0;
393		while ((ch = (u_char)*fmt++) != '%') {
394			if (ch == '\0')
395				return retval;
396			PCHAR(ch);
397		}
398		lflag = 0; ladjust = 0; sharpflag = 0; neg = 0;
399		sign = 0; dot = 0; dwidth = 0;
400reswitch:	switch (ch = (u_char)*fmt++) {
401		case '.':
402			dot = 1;
403			goto reswitch;
404		case '#':
405			sharpflag = 1;
406			goto reswitch;
407		case '+':
408			sign = 1;
409			goto reswitch;
410		case '-':
411			ladjust = 1;
412			goto reswitch;
413		case '%':
414			PCHAR(ch);
415			break;
416		case '*':
417			if (!dot) {
418				width = va_arg(ap, int);
419				if (width < 0) {
420					ladjust = !ladjust;
421					width = -width;
422				}
423			} else {
424				dwidth = va_arg(ap, int);
425			}
426			goto reswitch;
427		case '0':
428			if (!dot) {
429				padc = '0';
430				goto reswitch;
431			}
432		case '1': case '2': case '3': case '4':
433		case '5': case '6': case '7': case '8': case '9':
434				for (n = 0;; ++fmt) {
435					n = n * 10 + ch - '0';
436					ch = *fmt;
437					if (ch < '0' || ch > '9')
438						break;
439				}
440			if (dot)
441				dwidth = n;
442			else
443				width = n;
444			goto reswitch;
445		case 'b':
446			ul = va_arg(ap, int);
447			p = va_arg(ap, char *);
448			for (q = ksprintn(ul, *p++, NULL); *q;)
449				PCHAR(*q--);
450
451			if (!ul)
452				break;
453
454			for (tmp = 0; *p;) {
455				n = *p++;
456				if (ul & (1 << (n - 1))) {
457					PCHAR(tmp ? ',' : '<');
458					for (; (n = *p) > ' '; ++p)
459						PCHAR(n);
460					tmp = 1;
461				} else
462					for (; *p > ' '; ++p)
463						continue;
464			}
465			if (tmp)
466				PCHAR('>');
467			break;
468		case 'c':
469			PCHAR(va_arg(ap, int));
470			break;
471		case 'D':
472			up = va_arg(ap, u_char *);
473			p = va_arg(ap, char *);
474			if (!width)
475				width = 16;
476			while(width--) {
477				PCHAR(hex2ascii(*up >> 4));
478				PCHAR(hex2ascii(*up & 0x0f));
479				up++;
480				if (width)
481					for (q=p;*q;q++)
482						PCHAR(*q);
483			}
484			break;
485		case 'd':
486			ul = lflag ? va_arg(ap, long) : va_arg(ap, int);
487			sign = 1;
488			base = 10;
489			goto number;
490		case 'l':
491			lflag = 1;
492			goto reswitch;
493		case 'o':
494			ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
495			base = 8;
496			goto nosign;
497		case 'p':
498			ul = (u_long)va_arg(ap, void *);
499			base = 16;
500			sharpflag = 1;
501			goto nosign;
502		case 'n':
503		case 'r':
504			ul = lflag ? va_arg(ap, u_long) :
505			    sign ? (u_long)va_arg(ap, int) : va_arg(ap, u_int);
506			base = radix;
507			goto number;
508		case 's':
509			p = va_arg(ap, char *);
510			if (p == NULL)
511				p = "(null)";
512			if (!dot)
513				n = strlen (p);
514			else
515				for (n = 0; n < dwidth && p[n]; n++)
516					continue;
517
518			width -= n;
519
520			if (!ladjust && width > 0)
521				while (width--)
522					PCHAR(padc);
523			while (n--)
524				PCHAR(*p++);
525			if (ladjust && width > 0)
526				while (width--)
527					PCHAR(padc);
528			break;
529		case 'u':
530			ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
531			base = 10;
532			goto nosign;
533		case 'x':
534			ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
535			base = 16;
536			goto nosign;
537		case 'z':
538			ul = lflag ? va_arg(ap, u_long) :
539			    sign ? (u_long)va_arg(ap, int) : va_arg(ap, u_int);
540			base = 16;
541			goto number;
542nosign:			sign = 0;
543number:			if (sign && (long)ul < 0L) {
544				neg = 1;
545				ul = -(long)ul;
546			}
547			p = ksprintn(ul, base, &tmp);
548			if (sharpflag && ul != 0) {
549				if (base == 8)
550					tmp++;
551				else if (base == 16)
552					tmp += 2;
553			}
554			if (neg)
555				tmp++;
556
557			if (!ladjust && width && (width -= tmp) > 0)
558				while (width--)
559					PCHAR(padc);
560			if (neg)
561				PCHAR('-');
562			if (sharpflag && ul != 0) {
563				if (base == 8) {
564					PCHAR('0');
565				} else if (base == 16) {
566					PCHAR('0');
567					PCHAR('x');
568				}
569			}
570
571			while (*p)
572				PCHAR(*p--);
573
574			if (ladjust && width && (width -= tmp) > 0)
575				while (width--)
576					PCHAR(padc);
577
578			break;
579		default:
580			PCHAR('%');
581			if (lflag)
582				PCHAR('l');
583			PCHAR(ch);
584			break;
585		}
586	}
587#undef PCHAR
588}
589
590/*
591 * Put character in log buffer.
592 */
593static void
594msglogchar(int c, void *dummyarg)
595{
596	struct msgbuf *mbp;
597
598	if (c != '\0' && c != '\r' && c != 0177 && msgbufmapped) {
599		mbp = msgbufp;
600		mbp->msg_ptr[mbp->msg_bufx++] = c;
601		if (mbp->msg_bufx >= mbp->msg_size)
602			mbp->msg_bufx = 0;
603		/* If the buffer is full, keep the most recent data. */
604		if (mbp->msg_bufr == mbp->msg_bufx) {
605			if (++mbp->msg_bufr >= mbp->msg_size)
606				mbp->msg_bufr = 0;
607		}
608	}
609}
610
611void
612msgbufinit(void *ptr, size_t size)
613{
614	char *cp;
615
616	cp = (char *)ptr;
617	msgbufp = (struct msgbuf *) (cp + size - sizeof(*msgbufp));
618	if (msgbufp->msg_magic != MSG_MAGIC || msgbufp->msg_ptr != cp) {
619		bzero(cp, size);
620		msgbufp->msg_magic = MSG_MAGIC;
621		msgbufp->msg_size = (char *)msgbufp - cp;
622		msgbufp->msg_ptr = cp;
623	}
624	msgbufmapped = 1;
625}
626
627#include "opt_ddb.h"
628#ifdef DDB
629#include <ddb/ddb.h>
630
631DB_SHOW_COMMAND(msgbuf, db_show_msgbuf)
632{
633	int i, j;
634
635	if (!msgbufmapped) {
636		db_printf("msgbuf not mapped yet\n");
637		return;
638	}
639	db_printf("msgbufp = %p\n", msgbufp);
640	db_printf("magic = %x, size = %d, r= %d, w = %d, ptr = %p\n",
641	    msgbufp->msg_magic, msgbufp->msg_size, msgbufp->msg_bufr,
642	    msgbufp->msg_bufx, msgbufp->msg_ptr);
643	for (i = 0; i < msgbufp->msg_size; i++) {
644		j = (i + msgbufp->msg_bufr) % msgbufp->msg_size;
645		db_printf("%c", msgbufp->msg_ptr[j]);
646	}
647	db_printf("\n");
648}
649
650#endif /* DDB */
651