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