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