xref: /netbsd-src/sys/kern/kern_history.c (revision c9496f6b604074a9451a67df576a5b423068e71e)
1 /*	$NetBSD: kern_history.c,v 1.16 2017/11/03 22:45:14 pgoyette Exp $	 */
2 
3 /*
4  * Copyright (c) 1997 Charles D. Cranor and Washington University.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  *
27  * from: NetBSD: uvm_stat.c,v 1.36 2011/02/02 15:13:34 chuck Exp
28  * from: Id: uvm_stat.c,v 1.1.2.3 1997/12/19 15:01:00 mrg Exp
29  */
30 
31 /*
32  * subr_kernhist.c
33  */
34 
35 #include <sys/cdefs.h>
36 __KERNEL_RCSID(0, "$NetBSD: kern_history.c,v 1.16 2017/11/03 22:45:14 pgoyette Exp $");
37 
38 #include "opt_ddb.h"
39 #include "opt_kernhist.h"
40 #include "opt_syscall_debug.h"
41 #include "opt_usb.h"
42 #include "opt_uvmhist.h"
43 #include "opt_biohist.h"
44 #include "opt_sysctl.h"
45 
46 #include <sys/atomic.h>
47 #include <sys/param.h>
48 #include <sys/systm.h>
49 #include <sys/cpu.h>
50 #include <sys/sysctl.h>
51 #include <sys/kernhist.h>
52 #include <sys/kmem.h>
53 
54 #ifdef UVMHIST
55 #include <uvm/uvm.h>
56 #endif
57 
58 #ifdef USB_DEBUG
59 #include <dev/usb/usbhist.h>
60 #endif
61 
62 #ifdef BIOHIST
63 #include <sys/biohist.h>
64 #endif
65 
66 #ifdef SYSCALL_DEBUG
67 KERNHIST_DECL(scdebughist);
68 #endif
69 
70 struct addr_xlt {
71 	const char *addr;
72 	size_t len;
73 	uint32_t offset;
74 };
75 
76 /*
77  * globals
78  */
79 
80 struct kern_history_head kern_histories;
81 bool kernhist_sysctl_ready = 0;
82 
83 int kernhist_print_enabled = 1;
84 
85 int sysctl_hist_node;
86 
87 static int sysctl_kernhist_helper(SYSCTLFN_PROTO);
88 
89 #ifdef DDB
90 
91 /*
92  * prototypes
93  */
94 
95 void kernhist_dump(struct kern_history *,
96     void (*)(const char *, ...) __printflike(1, 2));
97 void kernhist_dumpmask(uint32_t);
98 static void kernhist_dump_histories(struct kern_history *[],
99     void (*)(const char *, ...) __printflike(1, 2));
100 
101 
102 /*
103  * call this from ddb
104  *
105  * expects the system to be quiesced, no locking
106  */
107 void
108 kernhist_dump(struct kern_history *l, void (*pr)(const char *, ...))
109 {
110 	int lcv;
111 
112 	lcv = l->f;
113 	do {
114 		if (l->e[lcv].fmt)
115 			kernhist_entry_print(&l->e[lcv], pr);
116 		lcv = (lcv + 1) % l->n;
117 	} while (lcv != l->f);
118 }
119 
120 /*
121  * print a merged list of kern_history structures
122  */
123 static void
124 kernhist_dump_histories(struct kern_history *hists[], void (*pr)(const char *, ...))
125 {
126 	struct bintime	bt;
127 	int	cur[MAXHISTS];
128 	int	lcv, hi;
129 
130 	/* find the first of each list */
131 	for (lcv = 0; hists[lcv]; lcv++)
132 		 cur[lcv] = hists[lcv]->f;
133 
134 	/*
135 	 * here we loop "forever", finding the next earliest
136 	 * history entry and printing it.  cur[X] is the current
137 	 * entry to test for the history in hists[X].  if it is
138 	 * -1, then this history is finished.
139 	 */
140 	for (;;) {
141 		hi = -1;
142 		bt.sec = 0; bt.frac = 0;
143 
144 		/* loop over each history */
145 		for (lcv = 0; hists[lcv]; lcv++) {
146 restart:
147 			if (cur[lcv] == -1)
148 				continue;
149 			if (!hists[lcv]->e)
150 				continue;
151 
152 			/*
153 			 * if the format is empty, go to the next entry
154 			 * and retry.
155 			 */
156 			if (hists[lcv]->e[cur[lcv]].fmt == NULL) {
157 				cur[lcv] = (cur[lcv] + 1) % (hists[lcv]->n);
158 				if (cur[lcv] == hists[lcv]->f)
159 					cur[lcv] = -1;
160 				goto restart;
161 			}
162 
163 			/*
164 			 * if the time hasn't been set yet, or this entry is
165 			 * earlier than the current bt, set the time and history
166 			 * index.
167 			 */
168 			if (bt.sec == 0 ||
169 			    bintimecmp(&hists[lcv]->e[cur[lcv]].bt, &bt, <)) {
170 				bt = hists[lcv]->e[cur[lcv]].bt;
171 				hi = lcv;
172 			}
173 		}
174 
175 		/* if we didn't find any entries, we must be done */
176 		if (hi == -1)
177 			break;
178 
179 		/* print and move to the next entry */
180 		kernhist_entry_print(&hists[hi]->e[cur[hi]], pr);
181 		cur[hi] = (cur[hi] + 1) % (hists[hi]->n);
182 		if (cur[hi] == hists[hi]->f)
183 			cur[hi] = -1;
184 	}
185 }
186 
187 /*
188  * call this from ddb.  `bitmask' is from <sys/kernhist.h>.  it
189  * merges the named histories.
190  *
191  * expects the system to be quiesced, no locking
192  */
193 void
194 kernhist_dumpmask(uint32_t bitmask)	/* XXX only support 32 hists */
195 {
196 	struct kern_history *hists[MAXHISTS + 1];
197 	int i = 0;
198 
199 #ifdef UVMHIST
200 	if ((bitmask & KERNHIST_UVMMAPHIST) || bitmask == 0)
201 		hists[i++] = &maphist;
202 
203 	if ((bitmask & KERNHIST_UVMPDHIST) || bitmask == 0)
204 		hists[i++] = &pdhist;
205 
206 	if ((bitmask & KERNHIST_UVMUBCHIST) || bitmask == 0)
207 		hists[i++] = &ubchist;
208 
209 	if ((bitmask & KERNHIST_UVMLOANHIST) || bitmask == 0)
210 		hists[i++] = &loanhist;
211 #endif
212 
213 #ifdef USB_DEBUG
214 	if ((bitmask & KERNHIST_USBHIST) || bitmask == 0)
215 		hists[i++] = &usbhist;
216 #endif
217 
218 #ifdef SYSCALL_DEBUG
219 	if ((bitmask & KERNHIST_SCDEBUGHIST) || bitmask == 0)
220 		hists[i++] = &scdebughist;
221 #endif
222 
223 #ifdef BIOHIST
224 	if ((bitmask & KERNHIST_BIOHIST) || bitmask == 0)
225 		hists[i++] = &biohist;
226 #endif
227 
228 	hists[i] = NULL;
229 
230 	kernhist_dump_histories(hists, printf);
231 }
232 
233 /*
234  * kernhist_print: ddb hook to print kern history
235  */
236 void
237 kernhist_print(void *addr, void (*pr)(const char *, ...) __printflike(1,2))
238 {
239 	struct kern_history *h;
240 
241 	LIST_FOREACH(h, &kern_histories, list) {
242 		if (h == addr)
243 			break;
244 	}
245 
246 	if (h == NULL) {
247 		struct kern_history *hists[MAXHISTS + 1];
248 		int i = 0;
249 #ifdef UVMHIST
250 		hists[i++] = &maphist;
251 		hists[i++] = &pdhist;
252 		hists[i++] = &ubchist;
253 		hists[i++] = &loanhist;
254 #endif
255 #ifdef USB_DEBUG
256 		hists[i++] = &usbhist;
257 #endif
258 
259 #ifdef SYSCALL_DEBUG
260 		hists[i++] = &scdebughist;
261 #endif
262 #ifdef BIOHIST
263 		hists[i++] = &biohist;
264 #endif
265 		hists[i] = NULL;
266 
267 		kernhist_dump_histories(hists, pr);
268 	} else {
269 		kernhist_dump(h, pr);
270 	}
271 }
272 
273 #endif
274 
275 /*
276  * sysctl interface
277  */
278 
279 /*
280  * sysctl_kernhist_new()
281  *
282  *	If the specified history (or, if no history is specified, any
283  *	history) does not already have a sysctl node (under kern.hist)
284  *	we create a new one and record it's node number.
285  */
286 void
287 sysctl_kernhist_new(struct kern_history *hist)
288 {
289 	int error;
290 	struct kern_history *h;
291 	const struct sysctlnode *rnode = NULL;
292 
293 	membar_consumer();
294 	if (kernhist_sysctl_ready == 0)
295 		return;
296 
297 	LIST_FOREACH(h, &kern_histories, list) {
298 		if (hist && h != hist)
299 			continue;
300 		if (h->s != 0)
301 			continue;
302 		error = sysctl_createv(NULL, 0, NULL, &rnode,
303 			    CTLFLAG_PERMANENT,
304 			    CTLTYPE_STRUCT, h->name,
305 			    SYSCTL_DESCR("history data"),
306 			    sysctl_kernhist_helper, 0, NULL, 0,
307 			    CTL_KERN, sysctl_hist_node, CTL_CREATE, CTL_EOL);
308 		if (error == 0)
309 			h->s = rnode->sysctl_num;
310 		if (hist == h)
311 			break;
312 	}
313 }
314 
315 /*
316  * sysctl_kerhnist_init()
317  *
318  *	Create the 2nd level "hw.hist" sysctl node
319  */
320 void
321 sysctl_kernhist_init(void)
322 {
323 	const struct sysctlnode *rnode = NULL;
324 
325 	sysctl_createv(NULL, 0, NULL, &rnode,
326 			CTLFLAG_PERMANENT,
327 			CTLTYPE_NODE, "hist",
328 			SYSCTL_DESCR("kernel history tables"),
329 			sysctl_kernhist_helper, 0, NULL, 0,
330 			CTL_KERN, CTL_CREATE, CTL_EOL);
331 	sysctl_hist_node = rnode->sysctl_num;
332 
333 	kernhist_sysctl_ready = 1;
334 	membar_producer();
335 
336 	sysctl_kernhist_new(NULL);
337 }
338 
339 /*
340  * find_string()
341  *
342  *	Search the address-to-offset translation table for matching an
343  *	address and len, and return the index of the entry we found.  If
344  *	not found, returns index 0 which points to the "?" entry.  (We
345  *	start matching at index 1, ignoring any matches of the "?" entry
346  *	itself.)
347  */
348 static int
349 find_string(struct addr_xlt table[], size_t *count, const char *string,
350 	    size_t len)
351 {
352 	int i;
353 
354 	for (i = 1; i < *count; i++)
355 		if (string == table[i].addr && len == table[i].len)
356 			return i;
357 
358 	return 0;
359 }
360 
361 /*
362  * add_string()
363  *
364  *	If the string and len are unique, add a new address-to-offset
365  *	entry in the translation table and set the offset of the next
366  *	entry.
367  */
368 static void
369 add_string(struct addr_xlt table[], size_t *count, const char *string,
370 	   size_t len)
371 {
372 
373 	if (find_string(table, count, string, len) == 0) {
374 		table[*count].addr = string;
375 		table[*count].len = len;
376 		table[*count + 1].offset = table[*count].offset + len + 1;
377 		(*count)++;
378 	}
379 }
380 
381 /*
382  * sysctl_kernhist_helper
383  *
384  *	This helper routine is called for all accesses to the kern.hist
385  *	hierarchy.
386  */
387 static int
388 sysctl_kernhist_helper(SYSCTLFN_ARGS)
389 {
390 	struct kern_history *h;
391 	struct kern_history_ent *in_evt;
392 	struct sysctl_history_event *out_evt;
393 	struct sysctl_history *buf;
394 	struct addr_xlt *xlate_t, *xlt;
395 	size_t bufsize, xlate_s;
396 	size_t xlate_c;
397 	const char *strp __diagused;
398 	char *next;
399 	int i, j;
400 	int error;
401 
402 	if (namelen == 1 && name[0] == CTL_QUERY)
403 		return sysctl_query(SYSCTLFN_CALL(rnode));
404 
405 	/*
406 	 * Disallow userland updates, verify that we arrived at a
407 	 * valid history rnode
408 	 */
409 	if (newp)
410 		return EPERM;
411 	if (namelen != 1 || name[0] != CTL_EOL)
412 		return EINVAL;
413 
414 	/* Find the correct kernhist for this sysctl node */
415 	LIST_FOREACH(h, &kern_histories, list) {
416 		if (h->s == rnode->sysctl_num)
417 			break;
418 	}
419 	if (h == NULL)
420 		return ENOENT;
421 
422 	/*
423 	 * Worst case is two string pointers per history entry, plus
424 	 * two for the history name and "?" string; allocate an extra
425 	 * entry since we pre-set the "next" entry's offset member.
426 	 */
427 	xlate_s = sizeof(struct addr_xlt) * h->n * 2 + 3;
428 	xlate_t = kmem_alloc(xlate_s, KM_SLEEP);
429 	xlate_c = 0;
430 
431 	/* offset 0 reserved for NULL pointer, ie unused history entry */
432 	xlate_t[0].offset = 1;
433 
434 	/*
435 	 * If the history gets updated and an unexpected string is
436 	 * found later, we'll point it here.  Otherwise, we'd have to
437 	 * repeat this process iteratively, and it could take multiple
438 	 * iterations before terminating.
439 	 */
440 	add_string(xlate_t, &xlate_c, "?", 0);
441 
442 	/* Copy the history name itself to the export structure */
443 	add_string(xlate_t, &xlate_c, h->name, h->namelen);
444 
445 	/*
446 	 * Loop through all used history entries to find the unique
447 	 * fn and fmt strings
448 	 */
449 	for (i = 0, in_evt = h->e; i < h->n; i++, in_evt++) {
450 		if (in_evt->fn == NULL)
451 			continue;
452 		add_string(xlate_t, &xlate_c, in_evt->fn, in_evt->fnlen);
453 		add_string(xlate_t, &xlate_c, in_evt->fmt, in_evt->fmtlen);
454 	}
455 
456 	/* Total buffer size includes header, events, and string table */
457 	bufsize = sizeof(struct sysctl_history) +
458 	    h->n * sizeof(struct sysctl_history_event) +
459 	    xlate_t[xlate_c].offset;
460 	buf = kmem_alloc(bufsize, KM_SLEEP);
461 
462 	/*
463 	 * Copy history header info to the export structure
464 	 */
465 	j = find_string(xlate_t, &xlate_c, h->name, h->namelen);
466 	buf->sh_nameoffset = xlate_t[j].offset;
467 	buf->sh_numentries = h->n;
468 	buf->sh_nextfree = h->f;
469 
470 	/*
471 	 * Loop through the history events again, copying the data to
472 	 * the export structure
473 	 */
474 	for (i = 0, in_evt = h->e, out_evt = buf->sh_events; i < h->n;
475 	    i++, in_evt++, out_evt++) {
476 		if (in_evt->fn == NULL) {	/* skip unused entries */
477 			out_evt->she_funcoffset = 0;
478 			out_evt->she_fmtoffset = 0;
479 			continue;
480 		}
481 		out_evt->she_bintime = in_evt->bt;
482 		out_evt->she_callnumber = in_evt->call;
483 		out_evt->she_cpunum = in_evt->cpunum;
484 		out_evt->she_values[0] = in_evt->v[0];
485 		out_evt->she_values[1] = in_evt->v[1];
486 		out_evt->she_values[2] = in_evt->v[2];
487 		out_evt->she_values[3] = in_evt->v[3];
488 		j = find_string(xlate_t, &xlate_c, in_evt->fn, in_evt->fnlen);
489 		out_evt->she_funcoffset = xlate_t[j].offset;
490 		j = find_string(xlate_t, &xlate_c, in_evt->fmt, in_evt->fmtlen);
491 		out_evt->she_fmtoffset = xlate_t[j].offset;
492 	}
493 
494 	/*
495 	 * Finally, fill the text string area with all the unique
496 	 * strings we found earlier.
497 	 *
498 	 * Skip the initial byte, since we use an offset of 0 to mean
499 	 * a NULL pointer (which means an unused history event).
500 	 */
501 	strp = next = (char *)(&buf->sh_events[h->n]);
502 	*next++ = '\0';
503 
504 	/*
505 	 * Then copy each string into the export structure, making
506 	 * sure to terminate each string with a '\0' character
507 	 */
508 	for (i = 0, xlt = xlate_t; i < xlate_c; i++, xlt++) {
509 		KASSERTMSG((next - strp) == xlt->offset,
510 		    "entry %d at wrong offset %"PRIu32, i, xlt->offset);
511 		memcpy(next, xlt->addr, xlt->len);
512 		next += xlt->len;
513 		*next++ = '\0';
514 	}
515 
516 	/* Copy data to userland */
517 	error = copyout(buf, oldp, min(bufsize, *oldlenp));
518 
519 	/* If copyout was successful but only partial, report ENOMEM */
520 	if (error == 0 && *oldlenp < bufsize)
521 		error = ENOMEM;
522 
523 	*oldlenp = bufsize;	/* inform userland of space requirements */
524 
525 	/* Free up the stuff we allocated */
526 	kmem_free(buf, bufsize);
527 	kmem_free(xlate_t, xlate_s);
528 
529 	return error;
530 }
531