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