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